blob: 7dd5ffcfddc8379ba2e8a12650b76e3ac9e782b3 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "BluetoothAvrcpServiceJni"
#define LOG_NDEBUG 0
#include "com_android_bluetooth.h"
#include "hardware/bt_rc.h"
#include "utils/Log.h"
#include "android_runtime/AndroidRuntime.h"
#include <string.h>
namespace android {
static jmethodID method_getRcFeatures;
static jmethodID method_getPlayStatus;
static jmethodID method_getElementAttr;
static jmethodID method_registerNotification;
static jmethodID method_volumeChangeCallback;
static jmethodID method_handlePassthroughCmd;
static jmethodID method_getFolderItemsCallback;
static jmethodID method_setAddressedPlayerCallback;
static jmethodID method_setBrowsedPlayerCallback;
static jmethodID method_changePathCallback;
static jmethodID method_searchCallback;
static jmethodID method_playItemCallback;
static jmethodID method_getItemAttrCallback;
static jmethodID method_addToPlayListCallback;
static jmethodID method_getTotalNumOfItemsCallback;
static const btrc_interface_t *sBluetoothAvrcpInterface = NULL;
static jobject mCallbacksObj = NULL;
/* Function declarations */
static bool copy_item_attributes(JNIEnv *env, jobject object, btrc_folder_items_t *pitem,
jint* p_attributesIds, jobjectArray attributesArray, int item_idx, int attribCopiedIndex);
static bool copy_jstring(uint8_t* str, int maxBytes, jstring jstr,JNIEnv* env);
static void cleanup_items(btrc_folder_items_t* p_items, int numItems);
static void btavrcp_remote_features_callback(bt_bdaddr_t* bd_addr,
btrc_remote_features_t features) {
jbyteArray addr;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Unable to allocate byte array for bd_addr");
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr, (jint)features);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(addr);
}
/** Callback for play status request */
static void btavrcp_get_play_status_callback(bt_bdaddr_t* bd_addr) {
jbyteArray addr;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for get_play_status command");
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_t *p_attrs,
bt_bdaddr_t *bd_addr) {
jbyteArray addr;
jintArray attrs;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for get_element_attr command");
return;
}
attrs = (jintArray)sCallbackEnv->NewIntArray(num_attr);
if (!attrs) {
ALOGE("Fail to new jintArray for attrs");
sCallbackEnv->DeleteLocalRef(addr);
return;
}
sCallbackEnv->SetIntArrayRegion(attrs, 0, num_attr, (jint *)p_attrs);
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, addr, (jbyte)num_attr,
attrs);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(attrs);
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_register_notification_callback(btrc_event_id_t event_id, uint32_t param,
bt_bdaddr_t *bd_addr) {
jbyteArray addr;
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for register_notification command");
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
addr, (jint)event_id, (jint)param);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype,
bt_bdaddr_t *bd_addr) {
jbyteArray addr;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for volume_change command");
return;
}
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback, addr, (jint)volume,
(jint)ctype);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_passthrough_command_callback(int id, int pressed,
bt_bdaddr_t* bd_addr) {
jbyteArray addr;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for passthrough_command command");
return;
}
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd, addr, (jint)id,
(jint)pressed);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_set_addressed_player_callback(uint16_t player_id,
bt_bdaddr_t *bd_addr) {
jbyteArray addr;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for set_addressed_player command");
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setAddressedPlayerCallback, addr, \
(jint) player_id);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_set_browsed_player_callback(uint16_t player_id, bt_bdaddr_t *bd_addr) {
jbyteArray addr;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for set_browsed_player command");
return;
}
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(
mCallbacksObj, method_setBrowsedPlayerCallback, addr, (jint) player_id);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_get_folder_items_callback(uint8_t scope, uint32_t start_item,
uint32_t end_item,uint8_t num_attr, uint32_t *p_attr_ids, bt_bdaddr_t *bd_addr) {
jbyteArray addr;
jintArray attr_ids = NULL;
uint32_t *puiAttr = (uint32_t *)p_attr_ids;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for get_folder_items command");
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
/* check number of attributes requested by remote device */
if ((num_attr != BTRC_NUM_ATTR_ALL) && (num_attr != BTRC_NUM_ATTR_NONE))
{
/* allocate memory for attr_ids only if some attributes passed from below layer */
attr_ids = (jintArray)sCallbackEnv->NewIntArray(num_attr);
if (!attr_ids) {
ALOGE("Fail to allocate new jintArray for attrs");
sCallbackEnv->DeleteLocalRef(addr);
return;
}
sCallbackEnv->SetIntArrayRegion(attr_ids, 0, num_attr, (jint *)puiAttr);
}
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getFolderItemsCallback, addr,
(jbyte) scope, (jint) start_item, (jint) end_item, (jbyte) num_attr, attr_ids);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
if (attr_ids != NULL) sCallbackEnv->DeleteLocalRef(attr_ids);
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_change_path_callback(uint8_t direction, uint8_t* folder_uid,
bt_bdaddr_t *bd_addr) {
jbyteArray addr;
jbyteArray attrs;;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
attrs = sCallbackEnv->NewByteArray(BTRC_UID_SIZE);
if (!attrs) {
ALOGE("Fail to new jintArray for attrs");
return;
}
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for change_path command");
sCallbackEnv->DeleteLocalRef(attrs);
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->SetByteArrayRegion(
attrs, 0, sizeof(uint8_t)*BTRC_UID_SIZE, (jbyte *)folder_uid);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_changePathCallback, addr,
(jbyte) direction, attrs);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(attrs);
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_get_item_attr_callback( uint8_t scope, uint8_t* uid, uint16_t uid_counter,
uint8_t num_attr, btrc_media_attr_t *p_attrs, bt_bdaddr_t *bd_addr) {
jbyteArray addr;
jintArray attrs;
jbyteArray attr_uid;
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
attr_uid = sCallbackEnv->NewByteArray(BTRC_UID_SIZE);
if (!attr_uid) {
ALOGE("Fail to new jintArray for attr_uid");
return;
}
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for get_item_attr command");
sCallbackEnv->DeleteLocalRef(attr_uid);
return;
}
attrs = (jintArray)sCallbackEnv->NewIntArray(num_attr);
if (!attrs) {
ALOGE("Fail to new jintArray for attrs");
sCallbackEnv->DeleteLocalRef(attr_uid);
sCallbackEnv->DeleteLocalRef(addr);
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->SetIntArrayRegion(attrs, 0, num_attr, (jint *)p_attrs);
sCallbackEnv->SetByteArrayRegion(attr_uid, 0, sizeof(uint8_t)*BTRC_UID_SIZE, (jbyte *)uid);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getItemAttrCallback, addr,
(jbyte) scope, attr_uid, (jint) uid_counter, (jbyte)num_attr, attrs);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(attr_uid);
sCallbackEnv->DeleteLocalRef(attrs);
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_play_item_callback(uint8_t scope, uint16_t uid_counter, uint8_t* uid,
bt_bdaddr_t *bd_addr) {
jbyteArray addr;
jbyteArray attrs;
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
attrs = sCallbackEnv->NewByteArray(BTRC_UID_SIZE);
if (!attrs) {
ALOGE("%s:Fail to new jByteArray attrs for play_item command", __func__);
return;
}
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for play_item command");
sCallbackEnv->DeleteLocalRef(attrs);
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->SetByteArrayRegion(attrs, 0, sizeof(uint8_t)*BTRC_UID_SIZE, (jbyte *)uid);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_playItemCallback, addr,
(jbyte) scope, (jint) uid_counter, attrs);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(attrs);
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_get_total_num_items_callback(uint8_t scope, bt_bdaddr_t *bd_addr) {
jbyteArray addr;
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for get_total_num_items command");
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->CallVoidMethod(
mCallbacksObj, method_getTotalNumOfItemsCallback, addr, (jbyte) scope);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_search_callback(uint16_t charset_id, uint16_t str_len, uint8_t* p_str,
bt_bdaddr_t *bd_addr) {
jbyteArray addr;
jbyteArray attrs;
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
attrs = sCallbackEnv->NewByteArray(str_len);
if (!attrs) {
ALOGE("Fail to new jintArray for attrs");
return;
}
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for search command");
sCallbackEnv->DeleteLocalRef(attrs);
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->SetByteArrayRegion(
attrs, 0, str_len*sizeof(uint8_t), (jbyte *)p_str);
sCallbackEnv->CallVoidMethod(
mCallbacksObj, method_searchCallback, addr, (jint) charset_id, attrs);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(attrs);
sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_add_to_play_list_callback(uint8_t scope,
uint8_t* uid, uint16_t uid_counter, bt_bdaddr_t *bd_addr) {
jbyteArray attrs;
jbyteArray addr;
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
ALOGE("Fail to new jbyteArray bd addr for add_to_play_list command");
return;
}
attrs = sCallbackEnv->NewByteArray(BTRC_UID_SIZE);
if (!attrs) {
ALOGE("Fail to new jByteArray for attrs");
sCallbackEnv->DeleteLocalRef(addr);
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
sCallbackEnv->SetByteArrayRegion(attrs, 0, sizeof(uint8_t)*BTRC_UID_SIZE, (jbyte *)uid);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_addToPlayListCallback, addr,
(jbyte) scope, attrs, (jint) uid_counter);
} else {
ALOGE("%s: mCallbacksObj is null", __func__);
}
sCallbackEnv->DeleteLocalRef(attrs);
sCallbackEnv->DeleteLocalRef(addr);
}
static btrc_callbacks_t sBluetoothAvrcpCallbacks = {
sizeof(sBluetoothAvrcpCallbacks),
btavrcp_remote_features_callback,
btavrcp_get_play_status_callback,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
btavrcp_get_element_attr_callback,
btavrcp_register_notification_callback,
btavrcp_volume_change_callback,
btavrcp_passthrough_command_callback,
btavrcp_set_addressed_player_callback,
btavrcp_set_browsed_player_callback,
btavrcp_get_folder_items_callback,
btavrcp_change_path_callback,
btavrcp_get_item_attr_callback,
btavrcp_play_item_callback,
btavrcp_get_total_num_items_callback,
btavrcp_search_callback,
btavrcp_add_to_play_list_callback,
};
static void classInitNative(JNIEnv* env, jclass clazz) {
method_getRcFeatures =
env->GetMethodID(clazz, "getRcFeaturesRequestFromNative", "([BI)V");
method_getPlayStatus =
env->GetMethodID(clazz, "getPlayStatusRequestFromNative", "([B)V");
method_getElementAttr =
env->GetMethodID(clazz, "getElementAttrRequestFromNative", "([BB[I)V");
method_registerNotification =
env->GetMethodID(clazz, "registerNotificationRequestFromNative", "([BII)V");
method_volumeChangeCallback =
env->GetMethodID(clazz, "volumeChangeRequestFromNative", "([BII)V");
method_handlePassthroughCmd =
env->GetMethodID(clazz, "handlePassthroughCmdRequestFromNative", "([BII)V");
method_setAddressedPlayerCallback =
env->GetMethodID(clazz, "setAddressedPlayerRequestFromNative", "([BI)V");
method_setBrowsedPlayerCallback =
env->GetMethodID(clazz, "setBrowsedPlayerRequestFromNative", "([BI)V");
method_getFolderItemsCallback =
env->GetMethodID(clazz, "getFolderItemsRequestFromNative", "([BBIIB[I)V");
method_changePathCallback =
env->GetMethodID(clazz, "changePathRequestFromNative", "([BB[B)V");
method_getItemAttrCallback =
env->GetMethodID(clazz, "getItemAttrRequestFromNative", "([BB[BIB[I)V");
method_playItemCallback =
env->GetMethodID(clazz, "playItemRequestFromNative", "([BBI[B)V");
method_getTotalNumOfItemsCallback =
env->GetMethodID(clazz, "getTotalNumOfItemsRequestFromNative", "([BB)V");
method_searchCallback =
env->GetMethodID(clazz, "searchRequestFromNative", "([BI[B)V");
method_addToPlayListCallback =
env->GetMethodID(clazz, "addToPlayListRequestFromNative", "([BB[BI)V");
ALOGI("%s: succeeds", __func__);
}
static void initNative(JNIEnv *env, jobject object) {
const bt_interface_t* btInf;
bt_status_t status;
if ( (btInf = getBluetoothInterface()) == NULL) {
ALOGE("Bluetooth module is not loaded");
return;
}
if (sBluetoothAvrcpInterface !=NULL) {
ALOGW("Cleaning up Avrcp Interface before initializing...");
sBluetoothAvrcpInterface->cleanup();
sBluetoothAvrcpInterface = NULL;
}
if (mCallbacksObj != NULL) {
ALOGW("Cleaning up Avrcp callback object");
env->DeleteGlobalRef(mCallbacksObj);
mCallbacksObj = NULL;
}
if ( (sBluetoothAvrcpInterface = (btrc_interface_t *)
btInf->get_profile_interface(BT_PROFILE_AV_RC_ID)) == NULL) {
ALOGE("Failed to get Bluetooth Avrcp Interface");
return;
}
if ( (status = sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks)) !=
BT_STATUS_SUCCESS) {
ALOGE("Failed to initialize Bluetooth Avrcp, status: %d", status);
sBluetoothAvrcpInterface = NULL;
return;
}
mCallbacksObj = env->NewGlobalRef(object);
}
static void cleanupNative(JNIEnv *env, jobject object) {
const bt_interface_t* btInf;
if ( (btInf = getBluetoothInterface()) == NULL) {
ALOGE("Bluetooth module is not loaded");
return;
}
if (sBluetoothAvrcpInterface !=NULL) {
sBluetoothAvrcpInterface->cleanup();
sBluetoothAvrcpInterface = NULL;
}
if (mCallbacksObj != NULL) {
env->DeleteGlobalRef(mCallbacksObj);
mCallbacksObj = NULL;
}
}
static jboolean getPlayStatusRspNative(JNIEnv *env, jobject object,
jbyteArray address, jint playStatus, jint songLen, jint songPos) {
bt_status_t status;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->get_play_status_rsp((bt_bdaddr_t*)btAddr,
(btrc_play_status_t)playStatus,songLen, songPos)) != BT_STATUS_SUCCESS) {
ALOGE("Failed get_play_status_rsp, status: %d", status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean getElementAttrRspNative(JNIEnv *env, jobject object,
jbyteArray address, jbyte numAttr, jintArray attrIds,
jobjectArray textArray) {
jint *attr;
bt_status_t status;
jstring text;
int attr_cnt;
btrc_element_attr_val_t *pAttrs = NULL;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
pAttrs = new btrc_element_attr_val_t[numAttr];
if (!pAttrs) {
ALOGE("get_element_attr_rsp: not have enough memeory");
env->ReleaseByteArrayElements(address, addr, 0);
return JNI_FALSE;
}
attr = env->GetIntArrayElements(attrIds, NULL);
if (!attr) {
delete[] pAttrs;
jniThrowIOException(env, EINVAL);
env->ReleaseByteArrayElements(address, addr, 0);
return JNI_FALSE;
}
for (attr_cnt = 0; attr_cnt < numAttr; ++attr_cnt) {
pAttrs[attr_cnt].attr_id = attr[attr_cnt];
text = (jstring) env->GetObjectArrayElement(textArray, attr_cnt);
if (!copy_jstring(pAttrs[attr_cnt].text, BTRC_MAX_ATTR_STR_LEN, text, env))
break;
env->DeleteLocalRef(text);
}
if (attr_cnt < numAttr) {
delete[] pAttrs;
env->DeleteLocalRef(text);
env->ReleaseIntArrayElements(attrIds, attr, 0);
ALOGE("%s: Failed to copy attributes", __func__);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->get_element_attr_rsp(btAddr, numAttr, pAttrs)) !=
BT_STATUS_SUCCESS) {
ALOGE("Failed get_element_attr_rsp, status: %d", status);
}
delete[] pAttrs;
env->ReleaseIntArrayElements(attrIds, attr, 0);
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean getItemAttrRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus, jbyte numAttr, jintArray attrIds, jobjectArray textArray) {
jint *attr = NULL;
bt_status_t status;
int attr_cnt;
btrc_element_attr_val_t *pAttrs = NULL;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
return JNI_FALSE;
}
pAttrs = new btrc_element_attr_val_t[numAttr];
if (!pAttrs) {
ALOGE("%s: not have enough memory", __func__);
env->ReleaseByteArrayElements(address, addr, 0);
return JNI_FALSE;
}
if (attrIds != NULL) {
attr = env->GetIntArrayElements(attrIds, NULL);
if (!attr) {
delete[] pAttrs;
jniThrowIOException(env, EINVAL);
env->ReleaseByteArrayElements(address, addr, 0);
return JNI_FALSE;
}
}
for (attr_cnt = 0; attr_cnt < numAttr; ++attr_cnt) {
pAttrs[attr_cnt].attr_id = attr[attr_cnt];
jstring text = (jstring) env->GetObjectArrayElement(textArray, attr_cnt);
if (!copy_jstring(pAttrs[attr_cnt].text, BTRC_MAX_ATTR_STR_LEN, text, env)) {
rspStatus = BTRC_STS_INTERNAL_ERR;
env->DeleteLocalRef(text);
ALOGE("%s: Failed to copy attributes", __func__);
break;
}
env->DeleteLocalRef(text);
}
if ((status = sBluetoothAvrcpInterface->get_item_attr_rsp(btAddr,
(btrc_status_t)rspStatus, numAttr, pAttrs)) != BT_STATUS_SUCCESS)
ALOGE("Failed get_item_attr_rsp, status: %d", status);
if (pAttrs) delete[] pAttrs;
if (attr) env->ReleaseIntArrayElements(attrIds, attr, 0);
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspPlayStatusNative(JNIEnv *env, jobject object,
jint type, jint playStatus) {
bt_status_t status;
btrc_register_notification_t param;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
param.play_status = (btrc_play_status_t)playStatus;
if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_STATUS_CHANGED,
(btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
ALOGE("Failed register_notification_rsp play status, status: %d", status);
}
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspTrackChangeNative(JNIEnv *env, jobject object,
jint type, jbyteArray track) {
bt_status_t status;
btrc_register_notification_t param;
jbyte *trk;
int uid_idx;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
trk = env->GetByteArrayElements(track, NULL);
if (!trk) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
for (uid_idx = 0; uid_idx < BTRC_UID_SIZE; ++uid_idx) {
param.track[uid_idx] = trk[uid_idx];
}
if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_TRACK_CHANGE,
(btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
ALOGE("Failed register_notification_rsp track change, status: %d", status);
}
env->ReleaseByteArrayElements(track, trk, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspPlayPosNative(JNIEnv *env, jobject object,
jint type, jint playPos) {
bt_status_t status;
btrc_register_notification_t param;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
param.song_pos = (uint32_t)playPos;
if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_POS_CHANGED,
(btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
ALOGE("Failed register_notification_rsp play position, status: %d", status);
}
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspNowPlayingChangedNative(
JNIEnv *env, jobject object,jint type) {
bt_status_t status;
btrc_register_notification_t param;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->register_notification_rsp(
BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED,
(btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS)
{
ALOGE("Failed register_notification_rsp, nowPlaying Content status: %d",
status);
}
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspUIDsChangedNative(
JNIEnv *env, jobject object,jint type, jint uidCounter) {
bt_status_t status;
btrc_register_notification_t param;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
param.uids_changed.uid_counter = (uint16_t)uidCounter;
if ((status = sBluetoothAvrcpInterface->register_notification_rsp(
BTRC_EVT_UIDS_CHANGED,
(btrc_notification_type_t)type,&param)) != BT_STATUS_SUCCESS)
{
ALOGE("Failed register_notification_rsp, uids changed status: %d",
status);
}
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspAddrPlayerChangedNative(JNIEnv *env,
jobject object, jint type, jint playerId, jint uidCounter) {
bt_status_t status;
btrc_register_notification_t param;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
param.addr_player_changed.player_id = (uint16_t)playerId;
param.addr_player_changed.uid_counter = (uint16_t)uidCounter;
if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_ADDR_PLAYER_CHANGE,
(btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
ALOGE("Failed register_notification_rsp address player changed status: %d", status);
}
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspAvalPlayerChangedNative(JNIEnv *env, jobject object,
jint type) {
bt_status_t status;
btrc_register_notification_t param;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_AVAL_PLAYER_CHANGE,
(btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
ALOGE("Failed register_notification_rsp available player changed status, status: %d",
status);
}
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume) {
bt_status_t status;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->set_volume((uint8_t)volume)) != BT_STATUS_SUCCESS) {
ALOGE("Failed set_volume, status: %d", status);
}
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
/* native response for scope as Media player */
static jboolean mediaPlayerListRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus, jint uidCounter,jbyte itemType,jint numItems,
jbyteArray playerTypes,jintArray playerSubtypes,
jbyteArray playStatusValues,
jshortArray featureBitmask,jobjectArray textArray) {
bt_status_t status;
btrc_folder_items_t *p_items = NULL;
int itemIdx = 0, InnCnt = 0;
jbyte* p_playerTypes = NULL,*p_PlayStatusValues = NULL;
jshort *p_FeatBitMaskValues = NULL;
jint *p_playerSubTypes = NULL;
jstring text;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if (rspStatus == BTRC_STS_NO_ERROR) {
/* allocate memory */
p_playerTypes = env->GetByteArrayElements(playerTypes, NULL);
p_playerSubTypes = env->GetIntArrayElements(playerSubtypes, NULL);
p_PlayStatusValues = env->GetByteArrayElements(playStatusValues, NULL);
p_FeatBitMaskValues = env->GetShortArrayElements(featureBitmask, NULL);
p_items = new btrc_folder_items_t[numItems];
/* deallocate memory and return if allocation failed */
if (!p_playerTypes || !p_playerSubTypes || !p_PlayStatusValues || !p_FeatBitMaskValues
|| !p_items) {
if (p_playerTypes) env->ReleaseByteArrayElements(playerTypes, p_playerTypes, 0);
if (p_playerSubTypes) env->ReleaseIntArrayElements(playerSubtypes,
p_playerSubTypes, 0);
if (p_PlayStatusValues) env->ReleaseByteArrayElements(playStatusValues,
p_PlayStatusValues , 0);
if (p_FeatBitMaskValues)
env->ReleaseShortArrayElements(featureBitmask, p_FeatBitMaskValues, 0);
if (p_items) delete[] p_items;
jniThrowIOException(env, EINVAL);
ALOGE("%s: not have enough memory", __func__);
return JNI_FALSE;
}
p_items->item_type = (uint8_t) itemType;
/* copy list of media players along with other parameters */
for (itemIdx = 0; itemIdx < numItems; ++itemIdx) {
p_items[itemIdx].player.player_id = (uint16_t)(itemIdx+1);
p_items[itemIdx].player.major_type = p_playerTypes[itemIdx];
p_items[itemIdx].player.sub_type = p_playerSubTypes[itemIdx];
p_items[itemIdx].player.play_status = p_PlayStatusValues[itemIdx];
p_items[itemIdx].player.charset_id = BTRC_CHARSET_ID_UTF8;
text = (jstring) env->GetObjectArrayElement(textArray, itemIdx);
/* copy player name */
if (!copy_jstring(p_items[itemIdx].player.name, BTRC_MAX_ATTR_STR_LEN, text, env))
break;
env->DeleteLocalRef(text);
/* Feature bit mask is 128-bit value each */
for (InnCnt=0; InnCnt < 16; InnCnt ++) {
p_items[itemIdx].player.features[InnCnt]
= (uint8_t)p_FeatBitMaskValues[(itemIdx*16) + InnCnt];
}
}
/* failed to copy list of media players */
if (itemIdx < numItems) {
rspStatus = BTRC_STS_INTERNAL_ERR;
ALOGE("%s: Failed to copy Media player attributes", __func__);
}
}
if ((status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(btAddr,
(btrc_status_t)rspStatus, uidCounter, numItems, p_items)) != BT_STATUS_SUCCESS) {
ALOGE("Failed get_folder_items_list_rsp, status: %d", status);
}
/* release allocated memory */
if (p_items) delete[] p_items;
if (p_playerTypes) env->ReleaseByteArrayElements(playerTypes, p_playerTypes, 0);
if (p_playerSubTypes) env->ReleaseIntArrayElements(playerSubtypes, p_playerSubTypes, 0);
if (p_PlayStatusValues) env->ReleaseByteArrayElements(playStatusValues, p_PlayStatusValues, 0);
if (p_FeatBitMaskValues) {
env->ReleaseShortArrayElements(featureBitmask, p_FeatBitMaskValues, 0);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean getFolderItemsRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus, jshort uidCounter,jbyte scope, jint numItems, jbyteArray folderType,
jbyteArray playable,jbyteArray itemType, jbyteArray itemUidArray,
jobjectArray displayNameArray, jintArray numAttrs, jintArray attributesIds,
jobjectArray attributesArray) {
jstring text; /* folder or item name */
bt_status_t status = BT_STATUS_SUCCESS;
jbyte *p_playable = NULL, *p_item_uid = NULL;
jbyte* p_item_types = NULL; /* Folder or Media Item */
jint* p_attributesIds = NULL;
jbyte* p_folder_types = NULL; /* Folder properties like Album/Genre/Artists etc */
jint* p_num_attrs = NULL;
btrc_folder_items_t *p_items = NULL;
int item_idx = 0;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
/* none of the parameters should be null when no error */
if (rspStatus == BTRC_STS_NO_ERROR) {
/* allocate memory to each rsp item */
if (folderType != NULL)
p_folder_types = env->GetByteArrayElements(folderType, NULL);
if (playable != NULL)
p_playable = env->GetByteArrayElements(playable, NULL);
if (itemType != NULL)
p_item_types = env->GetByteArrayElements(itemType, NULL);
if (NULL != numAttrs)
p_num_attrs = env->GetIntArrayElements(numAttrs, NULL);
if (NULL != attributesIds)
p_attributesIds = env->GetIntArrayElements(attributesIds, NULL);
if (itemUidArray != NULL)
p_item_uid = (jbyte*) env->GetByteArrayElements(itemUidArray, NULL);
p_items = new btrc_folder_items_t[numItems];
/* if memory alloc failed, release memory */
if (p_items && p_folder_types && p_playable && p_item_types && p_item_uid &&
/* attributes can be null if remote requests 0 attributes */
((numAttrs != NULL && p_num_attrs)||(!numAttrs && !p_num_attrs)) &&
((attributesIds != NULL && p_attributesIds)|| (!attributesIds && !p_attributesIds))) {
memset(p_items, 0, sizeof(btrc_folder_items_t)*numItems);
if (scope == BTRC_SCOPE_FILE_SYSTEM || scope == BTRC_SCOPE_SEARCH ||
scope == BTRC_SCOPE_NOW_PLAYING) {
int attribCopiedIndex = 0;
for (item_idx = 0; item_idx < numItems; item_idx++) {
if (BTRC_ITEM_FOLDER == p_item_types[item_idx]){
btrc_folder_items_t *pitem = &p_items[item_idx];
memcpy(pitem->folder.uid, p_item_uid + item_idx*BTRC_UID_SIZE,
BTRC_UID_SIZE);
pitem->item_type = (uint8_t)BTRC_ITEM_FOLDER;
pitem->folder.charset_id = BTRC_CHARSET_ID_UTF8;
pitem->folder.type = p_folder_types[item_idx];
pitem->folder.playable = p_playable[item_idx];
text = (jstring) env->GetObjectArrayElement(displayNameArray, item_idx);
if (!copy_jstring(pitem->folder.name, BTRC_MAX_ATTR_STR_LEN,
text, env)) {
rspStatus = BTRC_STS_INTERNAL_ERR;
env->DeleteLocalRef(text);
ALOGE("%s: failed to copy display name of folder item", __func__);
break;
}
env->DeleteLocalRef(text);
}
else if (BTRC_ITEM_MEDIA == p_item_types[item_idx])
{
btrc_folder_items_t *pitem = &p_items[item_idx];
memcpy(pitem->media.uid, p_item_uid + item_idx*BTRC_UID_SIZE,
BTRC_UID_SIZE);
pitem->item_type = (uint8_t)BTRC_ITEM_MEDIA;
pitem->media.charset_id = BTRC_CHARSET_ID_UTF8;
pitem->media.type = BTRC_MEDIA_TYPE_AUDIO;
pitem->media.num_attrs = (p_num_attrs != NULL) ?
p_num_attrs[item_idx] : 0;
text = (jstring) env->GetObjectArrayElement(displayNameArray, item_idx);
if (!copy_jstring(pitem->media.name, BTRC_MAX_ATTR_STR_LEN, text, env)){
rspStatus = BTRC_STS_INTERNAL_ERR;
env->DeleteLocalRef(text);
ALOGE("%s: failed to copy display name of media item", __func__);
break;
}
env->DeleteLocalRef(text);
/* copy item attributes */
if (!copy_item_attributes(env, object, pitem, p_attributesIds,
attributesArray, item_idx, attribCopiedIndex)) {
ALOGE("%s: error in copying attributes of item = %s",
__func__, pitem->media.name);
rspStatus = BTRC_STS_INTERNAL_ERR;
break;
}
attribCopiedIndex += pitem->media.num_attrs;
}
}
}
} else {
rspStatus = BTRC_STS_INTERNAL_ERR;
ALOGE("%s: unable to allocate memory", __func__);
}
}
if ((status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(btAddr,
(btrc_status_t)rspStatus, uidCounter,numItems,p_items)) != BT_STATUS_SUCCESS)
ALOGE("Failed get_folder_items_list_rsp, status: %d", status);
/* Release allocated memory for all attributes in each media item */
if (p_items)
cleanup_items(p_items, numItems);
/* Release allocated memory */
if (p_folder_types) env->ReleaseByteArrayElements(folderType, p_folder_types, 0);
if (p_playable) env->ReleaseByteArrayElements(playable, p_playable, 0);
if (p_item_types) env->ReleaseByteArrayElements(itemType, p_item_types, 0);
if (p_num_attrs) env->ReleaseIntArrayElements(numAttrs, p_num_attrs, 0);
if (p_attributesIds) env->ReleaseIntArrayElements(attributesIds, p_attributesIds, 0);
if (p_item_uid) env->ReleaseByteArrayElements(itemUidArray, p_item_uid, 0);
if (p_items) delete[] p_items;
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean setAddressedPlayerRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus) {
bt_status_t status;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->set_addressed_player_rsp(btAddr,
(btrc_status_t)rspStatus)) != BT_STATUS_SUCCESS) {
ALOGE("Failed set_addressed_player_rsp, status: %d", status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean setBrowsedPlayerRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus, jbyte depth, jint numItems, jobjectArray textArray) {
bt_status_t status;
bt_bdaddr_t * btAddr;
jbyte *addr;
uint16_t charset_id = BTRC_CHARSET_ID_UTF8;
uint8_t folder_depth = depth; /* folder_depth is 0 if current folder is root */
btrc_br_folder_name_t *p_folders = NULL;
int folder_idx = 0;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if (rspStatus == BTRC_STS_NO_ERROR) {
if (depth > 0)
p_folders = new btrc_br_folder_name_t[depth];
for (folder_idx = 0; folder_idx < depth; folder_idx++) {
/* copy folder names */
jstring text = (jstring) env->GetObjectArrayElement(textArray, folder_idx);
if (!copy_jstring(p_folders[folder_idx].p_str, BTRC_MAX_ATTR_STR_LEN,
text, env)) {
rspStatus = BTRC_STS_INTERNAL_ERR;
env->DeleteLocalRef(text);
delete[] p_folders;
env->ReleaseByteArrayElements(address, addr, 0);
ALOGE("%s: Failed to copy folder name", __func__);
return JNI_FALSE;
}
p_folders[folder_idx].str_len = strlen((char *)p_folders[folder_idx].p_str);
env->DeleteLocalRef(text);
}
}
if ((status = sBluetoothAvrcpInterface->set_browsed_player_rsp(btAddr,
(btrc_status_t) rspStatus, numItems, charset_id, folder_depth,
p_folders)) != BT_STATUS_SUCCESS) {
ALOGE("%s: Failed set_browsed_player_rsp, status: %d", __func__, status);
}
if (depth > 0)
delete[] p_folders;
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean changePathRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus, jint numItems) {
bt_status_t status;
uint32_t nItems = (uint32_t)numItems;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->change_path_rsp(btAddr, (btrc_status_t)rspStatus,
(uint32_t) nItems)) != BT_STATUS_SUCCESS) {
ALOGE("Failed change_path_rsp, status: %d", status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean searchRspNative(JNIEnv *env, jobject object, jbyteArray address, jint rspStatus,
jint uidCounter, jint numItems) {
bt_status_t status;
uint32_t nItems = (uint32_t)numItems;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->search_rsp(btAddr, (btrc_status_t)rspStatus,
(uint32_t) uidCounter, (uint32_t) nItems)) != BT_STATUS_SUCCESS) {
ALOGE("Failed search_rsp, status: %d", status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean playItemRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus) {
bt_status_t status;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->play_item_rsp(btAddr, (btrc_status_t)rspStatus))
!= BT_STATUS_SUCCESS) {
ALOGE("Failed play_item_rsp, status: %d", status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean getTotalNumOfItemsRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus, jint uidCounter, jint numItems) {
bt_status_t status;
uint32_t nItems = (uint32_t)numItems;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->get_total_num_of_items_rsp(btAddr,
(btrc_status_t)rspStatus, (uint32_t) uidCounter, (uint32_t) nItems))
!= BT_STATUS_SUCCESS) {
ALOGE("Failed get_total_num_of_items_rsp, status: %d", status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean addToNowPlayingRspNative(JNIEnv *env, jobject object, jbyteArray address,
jint rspStatus) {
bt_status_t status;
bt_bdaddr_t * btAddr;
jbyte *addr;
if (!sBluetoothAvrcpInterface) {
ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
return JNI_FALSE;
}
addr = env->GetByteArrayElements(address, NULL);
btAddr = (bt_bdaddr_t *) addr;
if (!addr) {
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
if ((status = sBluetoothAvrcpInterface->add_to_now_playing_rsp(btAddr,
(btrc_status_t)rspStatus)) != BT_STATUS_SUCCESS) {
ALOGE("Failed add_to_now_playing_rsp, status: %d", status);
}
env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void *) classInitNative},
{"initNative", "()V", (void *) initNative},
{"cleanupNative", "()V", (void *) cleanupNative},
{"getPlayStatusRspNative", "([BIII)Z", (void *) getPlayStatusRspNative},
{"getElementAttrRspNative", "([BB[I[Ljava/lang/String;)Z", (void *) getElementAttrRspNative},
{"registerNotificationRspPlayStatusNative", "(II)Z",
(void *) registerNotificationRspPlayStatusNative},
{"registerNotificationRspTrackChangeNative", "(I[B)Z",
(void *) registerNotificationRspTrackChangeNative},
{"registerNotificationRspPlayPosNative", "(II)Z",
(void *) registerNotificationRspPlayPosNative},
{"setVolumeNative", "(I)Z",
(void *) setVolumeNative},
{"setAddressedPlayerRspNative", "([BI)Z",
(void *) setAddressedPlayerRspNative},
{"setBrowsedPlayerRspNative", "([BIBI[Ljava/lang/String;)Z",
(void *) setBrowsedPlayerRspNative},
{"mediaPlayerListRspNative", "([BIIBI[B[I[B[S[Ljava/lang/String;)Z",
(void *) mediaPlayerListRspNative},
{"getFolderItemsRspNative",
"([BISBI[B[B[B[B[Ljava/lang/String;[I[I[Ljava/lang/String;)Z",
(void *) getFolderItemsRspNative},
{"changePathRspNative", "([BII)Z",
(void *) changePathRspNative},
{"getItemAttrRspNative", "([BIB[I[Ljava/lang/String;)Z",
(void *) getItemAttrRspNative},
{"playItemRspNative", "([BI)Z",
(void *) playItemRspNative},
{"getTotalNumOfItemsRspNative", "([BIII)Z",
(void *) getTotalNumOfItemsRspNative},
{"searchRspNative", "([BIII)Z",
(void *) searchRspNative},
{"addToNowPlayingRspNative", "([BI)Z",
(void *) addToNowPlayingRspNative},
{"registerNotificationRspAddrPlayerChangedNative", "(III)Z",
(void *) registerNotificationRspAddrPlayerChangedNative},
{"registerNotificationRspAvalPlayerChangedNative", "(I)Z",
(void *) registerNotificationRspAvalPlayerChangedNative},
{"registerNotificationRspUIDsChangedNative", "(II)Z",
(void *) registerNotificationRspUIDsChangedNative},
{"registerNotificationRspNowPlayingChangedNative", "(I)Z",
(void *) registerNotificationRspNowPlayingChangedNative}
};
int register_com_android_bluetooth_avrcp(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/bluetooth/avrcp/Avrcp",
sMethods, NELEM(sMethods));
}
/* Helper function to copy attributes of item.
* Assumes that all items in response have same number of attributes
*
* returns true on succes, false otherwise.
*/
static bool copy_item_attributes(JNIEnv *env, jobject object, btrc_folder_items_t *pitem,
jint* p_attributesIds, jobjectArray attributesArray, int item_idx, int attribCopiedIndex) {
bool success = true;
jstring text;
/* copy attributes of the item */
if (0 < pitem->media.num_attrs) {
int num_attrs = pitem->media.num_attrs;
ALOGI("%s num_attr = %d", __func__, num_attrs);
if (!(pitem->media.p_attrs = new btrc_element_attr_val_t[num_attrs])) {
return false;
}
for (int tempAtrCount = 0; tempAtrCount < pitem->media.num_attrs; ++tempAtrCount) {
pitem->media.p_attrs[tempAtrCount].attr_id =
p_attributesIds[attribCopiedIndex + tempAtrCount];
text = (jstring) env->GetObjectArrayElement(attributesArray,
attribCopiedIndex + tempAtrCount);
if (!copy_jstring(pitem->media.p_attrs[tempAtrCount].text, BTRC_MAX_ATTR_STR_LEN,
text, env)) {
success = false;
env->DeleteLocalRef(text);
ALOGE("%s: failed to copy attributes", __func__);
break;
}
env->DeleteLocalRef(text);
}
}
return success;
}
/* Helper function to copy String data from java to native
*
* returns true on succes, false otherwise
*/
static bool copy_jstring(uint8_t* str, int maxBytes, jstring jstr,JNIEnv* env) {
const char* p_str;
int len;
if (str == NULL || jstr == NULL || env == NULL)
return false;
memset(str, 0, maxBytes);
p_str = env->GetStringUTFChars(jstr, NULL);
len = strnlen(p_str, maxBytes-1);
memcpy(str, p_str, len);
env->ReleaseStringUTFChars(jstr, p_str);
return true;
}
/* Helper function to cleanup items */
static void cleanup_items(btrc_folder_items_t* p_items, int numItems) {
for (int item_idx = 0; item_idx < numItems; item_idx++) {
/* release memory for attributes in case item is media item */
if ((BTRC_ITEM_MEDIA == p_items[item_idx].item_type)
&& p_items[item_idx].media.p_attrs != NULL)
delete[] p_items[item_idx].media.p_attrs;
}
}
}