com_android_bluetooth_avrcp.cpp revision ace834feb02adabd61f628c4471147aea02d939c
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;
32ace834feb02adabd61f628c4471147aea02d939cJohn Dustatic jmethodID method_handlePassthroughCmd;
33c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
34c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic const btrc_interface_t *sBluetoothAvrcpInterface = NULL;
35c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jobject mCallbacksObj = NULL;
36c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic JNIEnv *sCallbackEnv = NULL;
37c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
38c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic bool checkCallbackThread() {
39c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // Always fetch the latest callbackEnv from AdapterService.
40c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // Caching this could cause this sCallbackEnv to go out-of-sync
41c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
42c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    // is received
43c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv = getCallbackEnv();
44c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
45c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    JNIEnv* env = AndroidRuntime::getJNIEnv();
46c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
47c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return true;
48c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
49c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
50c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void btavrcp_get_play_status_callback() {
51c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s", __FUNCTION__);
52c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
53c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!checkCallbackThread()) {
54c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
55c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
56c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
57c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
58c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus);
59c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
60c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
61c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
62c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_t *p_attrs) {
63c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    jintArray attrs;
64c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
65c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s", __FUNCTION__);
66c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
67c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!checkCallbackThread()) {
68c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
69c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
70c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
71c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    attrs = (jintArray)sCallbackEnv->NewIntArray(num_attr);
72c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!attrs) {
73c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Fail to new jintArray for attrs");
74c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
75c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
76c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
77c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->SetIntArrayRegion(attrs, 0, num_attr, (jint *)p_attrs);
78c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, (jbyte)num_attr, attrs);
79c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
80c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->DeleteLocalRef(attrs);
81c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
82c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
83c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void btavrcp_register_notification_callback(btrc_event_id_t event_id, uint32_t param) {
84c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s", __FUNCTION__);
85c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
86c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!checkCallbackThread()) {
87c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
88c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
89c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
90c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
91c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
92c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                 (jint)event_id, (jint)param);
93c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
94c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
95c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
96ace834feb02adabd61f628c4471147aea02d939cJohn Dustatic void btavrcp_passthrough_command_callback(int id, int pressed) {
97ace834feb02adabd61f628c4471147aea02d939cJohn Du    ALOGI("%s", __FUNCTION__);
98ace834feb02adabd61f628c4471147aea02d939cJohn Du
99ace834feb02adabd61f628c4471147aea02d939cJohn Du    if (!checkCallbackThread()) {
100ace834feb02adabd61f628c4471147aea02d939cJohn Du        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
101ace834feb02adabd61f628c4471147aea02d939cJohn Du        return;
102ace834feb02adabd61f628c4471147aea02d939cJohn Du    }
103ace834feb02adabd61f628c4471147aea02d939cJohn Du
104ace834feb02adabd61f628c4471147aea02d939cJohn Du    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd, (jint)id,
105ace834feb02adabd61f628c4471147aea02d939cJohn Du                                                                             (jint)pressed);
106ace834feb02adabd61f628c4471147aea02d939cJohn Du    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
107ace834feb02adabd61f628c4471147aea02d939cJohn Du}
108ace834feb02adabd61f628c4471147aea02d939cJohn Du
109c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic btrc_callbacks_t sBluetoothAvrcpCallbacks = {
110c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    sizeof(sBluetoothAvrcpCallbacks),
111c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btavrcp_get_play_status_callback,
112c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
113c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
114c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
115c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
116c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
117c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    NULL,
118c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btavrcp_get_element_attr_callback,
119ace834feb02adabd61f628c4471147aea02d939cJohn Du    btavrcp_register_notification_callback,
120ace834feb02adabd61f628c4471147aea02d939cJohn Du    btavrcp_passthrough_command_callback
121c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu};
122c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
123c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void classInitNative(JNIEnv* env, jclass clazz) {
124c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    method_getPlayStatus =
125c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->GetMethodID(clazz, "getPlayStatus", "()V");
126c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
127c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    method_getElementAttr =
128c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->GetMethodID(clazz, "getElementAttr", "(B[I)V");
129c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
130c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    method_registerNotification =
131c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->GetMethodID(clazz, "registerNotification", "(II)V");
132c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
133ace834feb02adabd61f628c4471147aea02d939cJohn Du    method_handlePassthroughCmd =
134ace834feb02adabd61f628c4471147aea02d939cJohn Du        env->GetMethodID(clazz, "handlePassthroughCmd", "(II)V");
135ace834feb02adabd61f628c4471147aea02d939cJohn Du
136c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s: succeeds", __FUNCTION__);
137c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
138c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
139c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void initNative(JNIEnv *env, jobject object) {
140c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    const bt_interface_t* btInf;
141c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
142c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
143c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ( (btInf = getBluetoothInterface()) == NULL) {
144c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Bluetooth module is not loaded");
145c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
146c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
147c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
148c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (sBluetoothAvrcpInterface !=NULL) {
149c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         ALOGW("Cleaning up Avrcp Interface before initializing...");
150c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         sBluetoothAvrcpInterface->cleanup();
151c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         sBluetoothAvrcpInterface = NULL;
152c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
153c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
154c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (mCallbacksObj != NULL) {
155c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         ALOGW("Cleaning up Avrcp callback object");
156c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         env->DeleteGlobalRef(mCallbacksObj);
157c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         mCallbacksObj = NULL;
158c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
159c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
160c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ( (sBluetoothAvrcpInterface = (btrc_interface_t *)
161c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu          btInf->get_profile_interface(BT_PROFILE_AV_RC_ID)) == NULL) {
162c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed to get Bluetooth Avrcp Interface");
163c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
164c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
165c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
166c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ( (status = sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks)) !=
167c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu         BT_STATUS_SUCCESS) {
168c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed to initialize Bluetooth Avrcp, status: %d", status);
169c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        sBluetoothAvrcpInterface = NULL;
170c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
171c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
172c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
173c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    mCallbacksObj = env->NewGlobalRef(object);
174c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
175c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
176c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic void cleanupNative(JNIEnv *env, jobject object) {
177c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    const bt_interface_t* btInf;
178c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
179c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ( (btInf = getBluetoothInterface()) == NULL) {
180c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Bluetooth module is not loaded");
181c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return;
182c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
183c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
184c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (sBluetoothAvrcpInterface !=NULL) {
185c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        sBluetoothAvrcpInterface->cleanup();
186c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        sBluetoothAvrcpInterface = NULL;
187c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
188c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
189c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (mCallbacksObj != NULL) {
190c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->DeleteGlobalRef(mCallbacksObj);
191c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        mCallbacksObj = NULL;
192c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
193c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
194c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
195c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jboolean getPlayStatusRspNative(JNIEnv *env, jobject object, jint playStatus,
196c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                       jint songLen, jint songPos) {
197c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
198c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
199c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
200c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
201c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
202c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ((status = sBluetoothAvrcpInterface->get_play_status_rsp((btrc_play_status_t)playStatus,
203c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                            songLen, songPos)) != BT_STATUS_SUCCESS) {
204c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed get_play_status_rsp, status: %d", status);
205c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
206c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
207c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
208c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
209c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
210c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu  static jboolean getElementAttrRspNative(JNIEnv *env, jobject object, jbyte numAttr,
211c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                          jintArray attrIds, jobjectArray textArray) {
212c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    jint *attr;
213c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
214c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    jstring text;
215c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    int i;
216c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btrc_element_attr_val_t *pAttrs = NULL;
217c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    const char* textStr;
218c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
219c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
220c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
221c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
222c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
223c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
224c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
225c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
226c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    pAttrs = new btrc_element_attr_val_t[numAttr];
227c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!pAttrs) {
228c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("get_element_attr_rsp: not have enough memeory");
229c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
230c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
231c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
232c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    attr = env->GetIntArrayElements(attrIds, NULL);
233c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!attr) {
234c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        delete[] pAttrs;
235c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        jniThrowIOException(env, EINVAL);
236c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
237c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
238c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
239c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    for (i = 0; i < numAttr; ++i) {
240c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        text = (jstring) env->GetObjectArrayElement(textArray, i);
241c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        textStr = env->GetStringUTFChars(text, NULL);
242c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (!textStr) {
243c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            ALOGE("get_element_attr_rsp: GetStringUTFChars return NULL");
244c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            env->DeleteLocalRef(text);
245c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            break;
246c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
247885213461ae72d6db178c95fafc01cde153230dbZhihai Xu
248885213461ae72d6db178c95fafc01cde153230dbZhihai Xu        pAttrs[i].attr_id = attr[i];
249c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        if (strlen(textStr) >= BTRC_MAX_ATTR_STR_LEN) {
250c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu            ALOGE("get_element_attr_rsp: string length exceed maximum");
251885213461ae72d6db178c95fafc01cde153230dbZhihai Xu            strncpy((char *)pAttrs[i].text, textStr, BTRC_MAX_ATTR_STR_LEN-1);
252885213461ae72d6db178c95fafc01cde153230dbZhihai Xu            pAttrs[i].text[BTRC_MAX_ATTR_STR_LEN-1] = 0;
253885213461ae72d6db178c95fafc01cde153230dbZhihai Xu        } else {
254885213461ae72d6db178c95fafc01cde153230dbZhihai Xu            strcpy((char *)pAttrs[i].text, textStr);
255c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        }
256c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->ReleaseStringUTFChars(text, textStr);
257c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->DeleteLocalRef(text);
258c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
259c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
260c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (i < numAttr) {
261c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        delete[] pAttrs;
262c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        env->ReleaseIntArrayElements(attrIds, attr, 0);
263c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
264c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
265c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
266c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ((status = sBluetoothAvrcpInterface->get_element_attr_rsp(numAttr, pAttrs)) !=
267c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        BT_STATUS_SUCCESS) {
268c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed get_element_attr_rsp, status: %d", status);
269c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
270c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
271c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    delete[] pAttrs;
272c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    env->ReleaseIntArrayElements(attrIds, attr, 0);
273c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
274c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
275c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
276c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jboolean registerNotificationRspPlayStatusNative(JNIEnv *env, jobject object,
277c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                                        jint type, jint playStatus) {
278c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
279c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btrc_register_notification_t param;
280c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
281c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
282c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
283c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
284c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    param.play_status = (btrc_play_status_t)playStatus;
285c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_STATUS_CHANGED,
286c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                  (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
287c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed register_notification_rsp play status, status: %d", status);
288c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
289c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
290c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
291c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
292c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
293c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic jboolean registerNotificationRspTrackChangeNative(JNIEnv *env, jobject object,
294c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                                         jint type, jbyteArray track) {
295c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    bt_status_t status;
296c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    btrc_register_notification_t param;
297c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    jbyte *trk;
298c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    int i;
299c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
300c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
301c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
302c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
303c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    trk = env->GetByteArrayElements(track, NULL);
304c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if (!trk) {
305c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        jniThrowIOException(env, EINVAL);
306c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        return JNI_FALSE;
307c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
308c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
309c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    for (i = 0; i < BTRC_UID_SIZE; ++i) {
310c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu      param.track[i] = trk[i];
311c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
312c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
313c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_TRACK_CHANGE,
314c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                  (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
315c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu        ALOGE("Failed register_notification_rsp track change, status: %d", status);
316c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    }
317c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
318c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    env->ReleaseByteArrayElements(track, trk, 0);
319c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
320c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
321c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
322aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xustatic jboolean registerNotificationRspPlayPosNative(JNIEnv *env, jobject object,
323aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                                                        jint type, jint playPos) {
324aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    bt_status_t status;
325aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    btrc_register_notification_t param;
326aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
327aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
328aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    if (!sBluetoothAvrcpInterface) return JNI_FALSE;
329aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
330aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    param.song_pos = (uint32_t)playPos;
331aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_POS_CHANGED,
332aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu                  (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
333aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu        ALOGE("Failed register_notification_rsp play position, status: %d", status);
334aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    }
335aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
336aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
337aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu}
338aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu
339c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xustatic JNINativeMethod sMethods[] = {
340c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"classInitNative", "()V", (void *) classInitNative},
341c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"initNative", "()V", (void *) initNative},
342c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"cleanupNative", "()V", (void *) cleanupNative},
343c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"getPlayStatusRspNative", "(III)Z", (void *) getPlayStatusRspNative},
344c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"getElementAttrRspNative", "(B[I[Ljava/lang/String;)Z", (void *) getElementAttrRspNative},
345c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"registerNotificationRspPlayStatusNative", "(II)Z",
346c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu     (void *) registerNotificationRspPlayStatusNative},
347c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    {"registerNotificationRspTrackChangeNative", "(I[B)Z",
348c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu     (void *) registerNotificationRspTrackChangeNative},
349aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu    {"registerNotificationRspPlayPosNative", "(II)Z",
350aa1ffd5c6bd4f016c6ed452b3551e65872eaea8eZhihai Xu     (void *) registerNotificationRspPlayPosNative},
351c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu};
352c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
353c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xuint register_com_android_bluetooth_avrcp(JNIEnv* env)
354c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu{
355c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu    return jniRegisterNativeMethods(env, "com/android/bluetooth/a2dp/Avrcp",
356c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu                                    sMethods, NELEM(sMethods));
357c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
358c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu
359c1c259c0ace7195240f1443c805995bfe8692a72Zhihai Xu}
360