summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGaurav Asati <gasati@codeaurora.org>2014-07-17 12:07:09 +0530
committerLinux Build Service Account <lnxbuild@localhost>2015-10-06 03:25:50 -0600
commit02bce8212bd482ecdb81c4a07896255fc01dcca1 (patch)
treebb50b2842f7d671f791b2da7724e0e3e71eddd2a
parent3f98885c96781357c38a1121a9dd7579cdd18f7f (diff)
downloadandroid_packages_apps_Bluetooth-02bce8212bd482ecdb81c4a07896255fc01dcca1.tar.gz
android_packages_apps_Bluetooth-02bce8212bd482ecdb81c4a07896255fc01dcca1.tar.bz2
android_packages_apps_Bluetooth-02bce8212bd482ecdb81c4a07896255fc01dcca1.zip
BT: Multi A2dp support in Bluetooth App.
1. Added support for Multi A2dp connections in Bluetooth application. 2. All connection transition states for 2nd HS onwards is handled in new state- MultiConnectionPending. 3. The changes are done to handle proper state transition for all connected HS. Change-Id: Ib7d16a4a647ba5d7e38a8c2edc4581474725ab6c Conflicts: src/com/android/bluetooth/avrcp/Avrcp.java src/com/android/bluetooth/btservice/AdapterService.java Bluetooth: Add support for multi Streaming. Add changes to support dual streaming for A2dp Change-Id: I84882d850ffd374bb998ef5e942464e2972d64bf Bluetooth: A2dp MultiCast/ Soft Hands-off. - Allow new profile connection on same ACL - Reset scan mode to last set scan mode before starting multicast - Check for mTargetDevice before moving to disconnected state. - Remove playing device from list on disconnect Change-Id: I24fa041783abba1584730930336b65a9586cb778 Bluetooth: Send Track change notification - Send track change notification to both devices. - Check for absolute volume support in both connected HS before updating audio - Reject 2nd incoming connection, when connecting event is received in pending state and already processing incoming connection. Change-Id: Ia5271febddcbf69c205fbebc7a11964a1ef0719c Dual A2DP: Update playstate on suspend - playstate update for suspend case to reflect the right state to remote device. Change-Id: If11acb9126ac8f424c622d786d4eaf3f155ca0c6 A2DP/AG: Increase A2DP/AG application level connection timeout - Application level connection timeout should be higher than lower level possible timeout to avoid race conditions. Stack level timeout for user response timeout is 30 seconds, hence during such scenarios stack will be still not timed out but application starts cleanup. Change-Id: I606e81fcea2e02c0cf4e5e47dba216bcbef42db4 Bluetooth: Update AudioManager for ABS volume - Update audiomanager for abs volume after RC features is received. - Update audiomanager when any of connected HS is disconnected. Change-Id: Ie2479cf538a830ba47c5a6418199caef2a81e78a Conflicts: src/com/android/bluetooth/avrcp/Avrcp.java Bluetooth: Block new ACL connections. - During active multicast, no new ACL should be created. - Do not proceed to new A2dp connection during active multicast. Change-Id: I0b9f6e7648976095ece8de4a41fbe10634c07131 Dual A2DP: Update currentDevice for unexpected disconnection - While in multipending state, currentDevice should be updated when disconnection is initiated for one device but happens for other device which is currentDevice. - Increase the connection timeout to 38 seconds to accomodate LMP response timeout and page timeout. CRs-Fixed: 835641 Change-Id: I54d439e458a212d6acf3031e5d1e89706071cfa9 Dual A2DP: Do not initiate bonding while multicast - Bonding has to be disabled while active multicast is on. This has to be explicitly taken care for avoiding the bonding and connection from available devices. Change-Id: Ic82686dd100201ca6171fbc3ab14c0b9690a850c CRs-Fixed: 837415 Misc A2dp Multicast Changes for proper Avrcp handling - Send play status update only if Music streaming is in progress. - Send play status update based on device specific stored state. - Remove multi player implementation as it causes mismatch in stored playback state and actual player state. - Logging changes for scan state update. CRs-Fixed: 839396 Change-Id: I539d949c32cbe1871f3c737bdd0e092798f729c1 Proper assignment of track number and play position - Initialize track number with value as -1 but on receiving meta update set it to 0 if media player in use is not capable of setting it to valid value. This change will help supporting 3rd party media player apps which are not capable of updating mentioned fields properly. - Explicitly send play-position as 0 in getPlayStatus response when position is not initialized as specification suggests that -1 is not a valid value for this command response. As per specification -1 will still be sent as the play position in interim response of Play Postion Changed notification. CRs-Fixed: 836672 Change-Id: I3e10ec4e49df095485fa630b95bf829e755686f1 Misc Avrcp handling for Multi connection scenarios - Handle avrcp TG connection state change update from stack and add remove respective devices to Avrcp connected device list. - Proper clean-up of device entries in A2dp and Handsfree state-machine. - Sending playback state changed as Paused when playback switches from that device to another. - Reject pending notifications when addressed player changes even to non 1.5 capable player. CRs-Fixed: 843335 Change-Id: Iafbeb17907e8bc5409ee996b966824fd4ba87417 Conflicts: src/com/android/bluetooth/avrcp/Avrcp.java Proper handling of Player settings attribute change - Proper handling of Player setting attribute change - Logging enhancement in player setting attrbute path. - Formatting changes. CRs-Fixed: 845462 Change-Id: I06067a091a21082b2668c31762f078da557841ee Conflicts: src/com/android/bluetooth/avrcp/Avrcp.java Dual A2DP: Update the connection state after timeout in Connected state When initiating incoming/outgoing connections, there is a possiblity that CONNECT_TIMEOUT for outgoing happens after successfully connecting to two other devices and this will be received in Connected state. We need to update the connection state and clear the target device. Change-Id: I0a1ad01f85b6f45b9276c6da9ce0e6b34f75990e Proper handling of Setting Addressed Player Proper handling of Setting Addressed Player ID. Make addressed Player ID as device independent. As otherwise device wont update the same after reconnection if any change has happened in between. CRs-Fixed: 855172 Change-Id: I23a4c3e9670fcd6538e0e3f5ef8c0be116a25de4 Change Play Position and Play status handling Change Play Position and Play status handling in a way that play positions are not kept device speific anymore as that belongs to change in player state, not device state. Play state changing to playing is sent only when device is identified as active one in hand-off mode. CRs-Fixed: 856063 Conflicts: src/com/android/bluetooth/a2dp/A2dpStateMachine.java Change-Id: Ia7e859c28a1826ac2686c432690030741a3c67bc
-rw-r--r--jni/com_android_bluetooth_a2dp.cpp46
-rw-r--r--jni/com_android_bluetooth_a2dp_sink.cpp15
-rw-r--r--jni/com_android_bluetooth_avrcp.cpp893
-rwxr-xr-xsrc/com/android/bluetooth/a2dp/A2dpService.java73
-rw-r--r--src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java11
-rw-r--r--src/com/android/bluetooth/a2dp/A2dpStateMachine.java1151
-rw-r--r--[-rwxr-xr-x]src/com/android/bluetooth/avrcp/Avrcp.java3140
-rw-r--r--src/com/android/bluetooth/btservice/AdapterService.java76
-rw-r--r--src/com/android/bluetooth/gatt/GattService.java19
-rwxr-xr-xsrc/com/android/bluetooth/hfp/HeadsetService.java10
-rwxr-xr-xsrc/com/android/bluetooth/hfp/HeadsetStateMachine.java146
-rw-r--r--src/com/android/bluetooth/hfpclient/HeadsetClientService.java9
-rw-r--r--src/com/android/bluetooth/hid/HidService.java10
-rw-r--r--src/com/android/bluetooth/opp/BluetoothOppTransfer.java11
-rw-r--r--[-rwxr-xr-x]src/com/android/bluetooth/pan/PanService.java9
15 files changed, 4260 insertions, 1359 deletions
diff --git a/jni/com_android_bluetooth_a2dp.cpp b/jni/com_android_bluetooth_a2dp.cpp
index ea2a8190b..e0d464a57 100644
--- a/jni/com_android_bluetooth_a2dp.cpp
+++ b/jni/com_android_bluetooth_a2dp.cpp
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,6 +32,8 @@ namespace android {
static jmethodID method_onConnectionStateChanged;
static jmethodID method_onAudioStateChanged;
static jmethodID method_onCheckConnectionPriority;
+static jmethodID method_onMulticastStateChanged;
+
static const btav_interface_t *sBluetoothA2dpInterface = NULL;
static jobject mCallbacksObj = NULL;
@@ -116,12 +121,26 @@ static void bta2dp_connection_priority_callback(bt_bdaddr_t* bd_addr) {
sCallbackEnv->DeleteLocalRef(addr);
}
+static void bta2dp_multicast_enabled_callback(int state) {
+
+ ALOGI("%s", __FUNCTION__);
+
+ if (!checkCallbackThread()) { \
+ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
+ return; \
+ }
+
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onMulticastStateChanged, state);
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+}
+
static btav_callbacks_t sBluetoothA2dpCallbacks = {
sizeof(sBluetoothA2dpCallbacks),
bta2dp_connection_state_callback,
bta2dp_audio_state_callback,
NULL,
- bta2dp_connection_priority_callback
+ bta2dp_connection_priority_callback,
+ bta2dp_multicast_enabled_callback,
};
static void classInitNative(JNIEnv* env, jclass clazz) {
@@ -137,6 +156,9 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
method_onCheckConnectionPriority =
env->GetMethodID(clazz, "onCheckConnectionPriority", "([B)V");
+
+ method_onMulticastStateChanged =
+ env->GetMethodID(clazz, "onMulticastStateChanged", "(I)V");
/*
if ( (btInf = getBluetoothInterface()) == NULL) {
ALOGE("Bluetooth module is not loaded");
@@ -162,7 +184,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
ALOGI("%s: succeeds", __FUNCTION__);
}
-static void initNative(JNIEnv *env, jobject object) {
+static void initNative(JNIEnv *env, jobject object, jint maxA2dpConnections,
+ jint multiCastState) {
const bt_interface_t* btInf;
bt_status_t status;
@@ -189,7 +212,8 @@ static void initNative(JNIEnv *env, jobject object) {
return;
}
- if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) {
+ if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks,
+ maxA2dpConnections, multiCastState)) != BT_STATUS_SUCCESS) {
ALOGE("Failed to initialize Bluetooth A2DP, status: %d", status);
sBluetoothA2dpInterface = NULL;
return;
@@ -259,24 +283,32 @@ static jboolean disconnectA2dpNative(JNIEnv *env, jobject object, jbyteArray add
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
-static void allowConnectionNative(JNIEnv *env, jobject object, int isValid) {
+static void allowConnectionNative(JNIEnv *env, jobject object, int is_valid, jbyteArray address) {
+ jbyte *addr;
if (!sBluetoothA2dpInterface) {
ALOGE("sBluetoothA2dpInterface is NULL ");
return;
}
- sBluetoothA2dpInterface->allowConnection(isValid);
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return ;
+ }
+
+ sBluetoothA2dpInterface->allow_connection(is_valid, (bt_bdaddr_t *)addr);
+ env->ReleaseByteArrayElements(address, addr, 0);
}
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void *) classInitNative},
- {"initNative", "()V", (void *) initNative},
+ {"initNative", "(II)V", (void *) initNative},
{"cleanupNative", "()V", (void *) cleanupNative},
{"connectA2dpNative", "([B)Z", (void *) connectA2dpNative},
{"disconnectA2dpNative", "([B)Z", (void *) disconnectA2dpNative},
- {"allowConnectionNative", "(I)V", (void *) allowConnectionNative},
+ {"allowConnectionNative", "(I[B)V", (void *) allowConnectionNative},
};
int register_com_android_bluetooth_a2dp(JNIEnv* env)
diff --git a/jni/com_android_bluetooth_a2dp_sink.cpp b/jni/com_android_bluetooth_a2dp_sink.cpp
index f2bbb1bc2..373e3895a 100644
--- a/jni/com_android_bluetooth_a2dp_sink.cpp
+++ b/jni/com_android_bluetooth_a2dp_sink.cpp
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -120,7 +123,9 @@ static btav_callbacks_t sBluetoothA2dpCallbacks = {
sizeof(sBluetoothA2dpCallbacks),
bta2dp_connection_state_callback,
bta2dp_audio_state_callback,
- bta2dp_audio_config_callback
+ bta2dp_audio_config_callback,
+ NULL,
+ NULL
};
static void classInitNative(JNIEnv* env, jclass clazz) {
@@ -140,7 +145,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
ALOGI("%s: succeeds", __FUNCTION__);
}
-static void initNative(JNIEnv *env, jobject object) {
+static void initNative(JNIEnv *env, jobject object, jint maxA2dpConnections,
+ jint multiCastState) {
const bt_interface_t* btInf;
bt_status_t status;
@@ -167,7 +173,8 @@ static void initNative(JNIEnv *env, jobject object) {
return;
}
- if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) {
+ if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks,
+ maxA2dpConnections, multiCastState)) != BT_STATUS_SUCCESS) {
ALOGE("Failed to initialize Bluetooth A2DP Sink, status: %d", status);
sBluetoothA2dpInterface = NULL;
return;
@@ -239,7 +246,7 @@ static jboolean disconnectA2dpNative(JNIEnv *env, jobject object, jbyteArray add
static JNINativeMethod sMethods[] = {
{"classInitNative", "()V", (void *) classInitNative},
- {"initNative", "()V", (void *) initNative},
+ {"initNative", "(II)V", (void *) initNative},
{"cleanupNative", "()V", (void *) cleanupNative},
{"connectA2dpNative", "([B)Z", (void *) connectA2dpNative},
{"disconnectA2dpNative", "([B)Z", (void *) disconnectA2dpNative},
diff --git a/jni/com_android_bluetooth_avrcp.cpp b/jni/com_android_bluetooth_avrcp.cpp
index 79c0c43dd..701679853 100644
--- a/jni/com_android_bluetooth_avrcp.cpp
+++ b/jni/com_android_bluetooth_avrcp.cpp
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,7 +50,7 @@ static jmethodID method_getplayerattribute_text;
static jmethodID method_getplayervalue_text;
static jmethodID method_onConnectionStateChanged;
-static const btrc_interface_t *sBluetoothAvrcpInterface = NULL;
+static const btrc_interface_t *sBluetoothMultiAvrcpInterface = NULL;
static jobject mCallbacksObj = NULL;
static JNIEnv *sCallbackEnv = NULL;
@@ -73,78 +76,119 @@ static void btavrcp_remote_features_callback(bt_bdaddr_t* bd_addr, btrc_remote_f
}
addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
if (!addr) {
- ALOGE("Unable to allocate byte array for bd_addr");
+ ALOGE("Fail to new jbyteArray bd addr for remote features");
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
return;
}
if (mCallbacksObj) {
sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr, (jint)features);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr,
+ (jint)features, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
- /* TODO: I think we leak the addr object, we should add a
- * sCallbackEnv->DeleteLocalRef(addr) */
+ sCallbackEnv->DeleteLocalRef(addr);
+
}
-static void btavrcp_get_play_status_callback() {
+static void btavrcp_get_play_status_callback(bt_bdaddr_t* bd_addr) {
ALOGI("%s", __FUNCTION__);
+ jbyteArray addr;
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for get play status");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_get_player_seeting_value_callback(btrc_player_attr_t player_att) {
+static void btavrcp_get_player_seeting_value_callback(btrc_player_attr_t player_att,
+ bt_bdaddr_t* bd_addr) {
ALOGI("%s", __FUNCTION__);
+ jbyteArray addr;
+
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for player seeting");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj ,method_onListPlayerAttributeValues,
- (jbyte)player_att);
+ (jbyte)player_att, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_get_player_attribute_id_callback() {
+static void btavrcp_get_player_attribute_id_callback(bt_bdaddr_t* bd_addr) {
ALOGI("%s", __FUNCTION__);
+ jbyteArray addr;
+
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for player attribute");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
- sCallbackEnv->CallVoidMethod(mCallbacksObj,method_onListPlayerAttributeRequest);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj,method_onListPlayerAttributeRequest, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_getcurrent_player_app_setting_values( uint8_t num_attr,
- btrc_player_attr_t *p_attrs) {
+ btrc_player_attr_t *p_attrs,
+ bt_bdaddr_t* bd_addr) {
jintArray attrs;
ALOGI("%s", __FUNCTION__);
+ jbyteArray addr;
+
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for player app setting");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
attrs = (jintArray)sCallbackEnv->NewIntArray(num_attr);
if (!attrs) {
ALOGE("Fail to new jintArray for attrs");
@@ -155,24 +199,35 @@ static void btavrcp_getcurrent_player_app_setting_values( uint8_t num_attr,
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj,method_onGetPlayerAttributeValues,
- (jbyte)num_attr,attrs);
+ (jbyte)num_attr,attrs, addr);
}
else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
sCallbackEnv->DeleteLocalRef(attrs);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_set_playerapp_setting_value_callback(btrc_player_settings_t *attr)
+static void btavrcp_set_playerapp_setting_value_callback(btrc_player_settings_t *attr,
+ bt_bdaddr_t* bd_addr)
{
jbyteArray attrs_ids;
jbyteArray attrs_value;
ALOGI("%s", __FUNCTION__);
+ jbyteArray addr;
+
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for set playerapp");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
attrs_ids = (jbyteArray)sCallbackEnv->NewByteArray(attr->num_attr);
if (!attrs_ids) {
ALOGE("Fail to new jintArray for attrs");
@@ -189,22 +244,33 @@ static void btavrcp_set_playerapp_setting_value_callback(btrc_player_settings_t
sCallbackEnv->SetByteArrayRegion(attrs_value, 0, attr->num_attr, (jbyte *)attr->attr_values);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setPlayerAppSetting,
- (jbyte)attr->num_attr ,attrs_ids ,attrs_value);
+ (jbyte)attr->num_attr ,attrs_ids ,attrs_value, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
sCallbackEnv->DeleteLocalRef(attrs_ids);
sCallbackEnv->DeleteLocalRef(attrs_value);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_getPlayer_app_attribute_text(uint8_t num , btrc_player_attr_t *att)
+static void btavrcp_getPlayer_app_attribute_text(uint8_t num , btrc_player_attr_t *att,
+ bt_bdaddr_t* bd_addr)
{
jbyteArray attrs;
ALOGI("%s", __FUNCTION__);
+ jbyteArray addr;
+
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for getPlayer app");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
attrs = (jbyteArray)sCallbackEnv->NewByteArray(num);
if (!attrs) {
ALOGE("Fail to new jintArray for attrs");
@@ -214,21 +280,32 @@ static void btavrcp_getPlayer_app_attribute_text(uint8_t num , btrc_player_attr_
sCallbackEnv->SetByteArrayRegion(attrs, 0, num, (jbyte *)att);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getplayerattribute_text,
- (jbyte) num ,attrs);
+ (jbyte) num ,attrs, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
sCallbackEnv->DeleteLocalRef(attrs);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_getPlayer_app_value_text(uint8_t attr_id , uint8_t num_val , uint8_t *value)
+static void btavrcp_getPlayer_app_value_text(uint8_t attr_id , uint8_t num_val , uint8_t *value,
+ bt_bdaddr_t* bd_addr)
{
jbyteArray Attr_Value ;
ALOGI("%s", __FUNCTION__);
+ jbyteArray addr;
+
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for getPlayer app");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
Attr_Value = (jbyteArray)sCallbackEnv->NewByteArray(num_val);
if (!Attr_Value) {
ALOGE("Fail to new jintArray for attrs");
@@ -238,15 +315,17 @@ static void btavrcp_getPlayer_app_value_text(uint8_t attr_id , uint8_t num_val ,
sCallbackEnv->SetByteArrayRegion(Attr_Value, 0, num_val, (jbyte *)value);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getplayervalue_text,(jbyte) attr_id,
- (jbyte) num_val , Attr_Value);
+ (jbyte) num_val , Attr_Value, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
sCallbackEnv->DeleteLocalRef(Attr_Value);
}
-static void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_t *p_attrs) {
+static void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_t *p_attrs,
+ bt_bdaddr_t* bd_addr) {
jintArray attrs;
+ jbyteArray addr;
ALOGI("%s", __FUNCTION__);
@@ -254,6 +333,13 @@ static void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for element attr");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
attrs = (jintArray)sCallbackEnv->NewIntArray(num_attr);
if (!attrs) {
ALOGE("Fail to new jintArray for attrs");
@@ -262,58 +348,90 @@ static void btavrcp_get_element_attr_callback(uint8_t num_attr, btrc_media_attr_
}
sCallbackEnv->SetIntArrayRegion(attrs, 0, num_attr, (jint *)p_attrs);
if (mCallbacksObj) {
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, (jbyte)num_attr, attrs);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, (jbyte)num_attr,
+ attrs, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
sCallbackEnv->DeleteLocalRef(attrs);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_register_notification_callback(btrc_event_id_t event_id, uint32_t param) {
+static void btavrcp_register_notification_callback(btrc_event_id_t event_id, uint32_t param,
+ bt_bdaddr_t* bd_addr) {
+ jbyteArray addr;
+ ALOGI("%s", __FUNCTION__);
+
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for register notification");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
- (jint)event_id, (jint)param);
+ (jint)event_id, (jint)param, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype) {
+static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype, bt_bdaddr_t* bd_addr) {
+
+ jbyteArray addr;
ALOGI("%s", __FUNCTION__);
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for volume change");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback, (jint)volume,
- (jint)ctype);
+ (jint)ctype, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_get_folder_items_callback(btrc_browse_folderitem_t scope ,
- btrc_getfolderitem_t *param) {
+ btrc_getfolderitem_t *param,
+ bt_bdaddr_t* bd_addr) {
jlong start = param->start_item;
jlong end = param->end_item;
jint size = param->size;
jint num_attr = param->attr_count;
jintArray attrs;
+ jbyteArray addr;
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
-
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for get folder items");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (num_attr == 0xff) {
num_attr = 0; // 0xff signifies no attribute required in response
} else if (num_attr == 0) {
@@ -336,32 +454,43 @@ static void btavrcp_get_folder_items_callback(btrc_browse_folderitem_t scope ,
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getFolderItems, (jbyte)scope,
- start, end, size, num_attr, attrs);
+ start, end, size, num_attr, attrs, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
sCallbackEnv->DeleteLocalRef(attrs);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_passthrough_command_callback(int id, int pressed) {
+static void btavrcp_passthrough_command_callback(int id, int pressed , bt_bdaddr_t* bd_addr) {
+ jbyteArray addr;
ALOGI("%s", __FUNCTION__);
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for passthrough command");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd,
- (jint)id, (jint)pressed);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd, (jint)id,
+ (jint)pressed, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_set_addressed_player_callback(uint32_t player_id) {
+static void btavrcp_set_addressed_player_callback(uint32_t player_id, bt_bdaddr_t* bd_addr) {
+ jbyteArray addr;
ALOGI("%s", __FUNCTION__);
ALOGI("player id: %d", player_id);
@@ -369,17 +498,27 @@ static void btavrcp_set_addressed_player_callback(uint32_t player_id) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for set addressed player");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setAddressedPlayer, (jint)player_id);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setAddressedPlayer, (jint)player_id,
+ addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_set_browsed_player_callback(uint32_t player_id) {
+static void btavrcp_set_browsed_player_callback(uint32_t player_id, bt_bdaddr_t* bd_addr) {
+ jbyteArray addr;
ALOGI("%s", __FUNCTION__);
ALOGI("player id: %d", player_id);
@@ -387,15 +526,25 @@ static void btavrcp_set_browsed_player_callback(uint32_t player_id) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for set browsed player");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setBrowsedPlayer, (jint)player_id);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setBrowsedPlayer, (jint)player_id,
+ addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_change_path_callback(uint8_t direction, uint64_t uid) {
+static void btavrcp_change_path_callback(uint8_t direction, uint64_t uid, bt_bdaddr_t* bd_addr) {
+ jbyteArray addr;
ALOGI("%s", __FUNCTION__);
ALOGI("direction: %d, uid: %lu", direction, uid);
@@ -403,16 +552,25 @@ static void btavrcp_change_path_callback(uint8_t direction, uint64_t uid) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for change path");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_changePath, (jbyte)direction,
- (jlong)uid);
+ (jlong)uid, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
-static void btavrcp_play_item_callback(uint8_t scope, uint64_t uid) {
+static void btavrcp_play_item_callback(uint8_t scope, uint64_t uid, bt_bdaddr_t* bd_addr) {
+ jbyteArray addr;
ALOGI("%s", __FUNCTION__);
ALOGI("scope: %d, uid: %lu", scope, uid);
@@ -420,18 +578,29 @@ static void btavrcp_play_item_callback(uint8_t scope, uint64_t uid) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for play item");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
if (mCallbacksObj) {
- sCallbackEnv->CallVoidMethod(mCallbacksObj, method_playItem, (jbyte)scope, (jlong)uid);
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_playItem, (jbyte)scope, (jlong)uid,
+ addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
static void btavrcp_get_item_attr_callback(uint8_t scope, uint64_t uid,
- uint8_t num_attr, btrc_media_attr_t *p_attrs) {
+ uint8_t num_attr, btrc_media_attr_t *p_attrs,
+ bt_bdaddr_t* bd_addr) {
jintArray attrs;
+ jbyteArray addr;
if (num_attr == 0xff) {
num_attr = 0; // 0xff signifies no attribute required in response
@@ -445,6 +614,13 @@ static void btavrcp_get_item_attr_callback(uint8_t scope, uint64_t uid,
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for get item attr");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
attrs = (jintArray)sCallbackEnv->NewIntArray(num_attr);
if (!attrs) {
ALOGE("Fail to new jintArray for attrs");
@@ -454,14 +630,46 @@ static void btavrcp_get_item_attr_callback(uint8_t scope, uint64_t uid,
sCallbackEnv->SetIntArrayRegion(attrs, 0, num_attr, (jint *)p_attrs);
if (mCallbacksObj) {
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getItemAttr, (jbyte)scope, (jlong)uid,
- (jbyte)num_attr, attrs);
+ (jbyte)num_attr, attrs, addr);
} else {
ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
}
checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
sCallbackEnv->DeleteLocalRef(attrs);
+ sCallbackEnv->DeleteLocalRef(addr);
+}
+
+static void btavrcp_connection_state_callback(bool state, bt_bdaddr_t* bd_addr) {
+ jbyteArray addr;
+
+ ALOGI("%s", __FUNCTION__);
+ ALOGI("conn state: %d", state);
+
+ if (!checkCallbackThread()) {
+ ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
+ return;
+ }
+
+ addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
+ if (!addr) {
+ ALOGE("Fail to new jbyteArray bd addr for connection state");
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ return;
+ }
+
+ sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
+ if (mCallbacksObj) {
+ sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
+ (jboolean) state, addr);
+ } else {
+ ALOGE("%s: mCallbacksObj is null", __FUNCTION__);
+ }
+ checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
+ sCallbackEnv->DeleteLocalRef(addr);
}
+
+
static btrc_callbacks_t sBluetoothAvrcpCallbacks = {
sizeof(sBluetoothAvrcpCallbacks),
btavrcp_remote_features_callback,
@@ -481,52 +689,56 @@ static btrc_callbacks_t sBluetoothAvrcpCallbacks = {
btavrcp_set_browsed_player_callback,
btavrcp_change_path_callback,
btavrcp_play_item_callback,
- btavrcp_get_item_attr_callback
+ btavrcp_get_item_attr_callback,
+ btavrcp_connection_state_callback
};
static void classInitNative(JNIEnv* env, jclass clazz) {
method_getRcFeatures =
env->GetMethodID(clazz, "getRcFeatures", "([BI)V");
method_getPlayStatus =
- env->GetMethodID(clazz, "getPlayStatus", "()V");
+ env->GetMethodID(clazz, "getPlayStatus", "([B)V");
method_onListPlayerAttributeRequest =
- env->GetMethodID(clazz , "onListPlayerAttributeRequest" , "()V");
+ env->GetMethodID(clazz , "onListPlayerAttributeRequest" , "([B)V");
method_onListPlayerAttributeValues =
- env->GetMethodID(clazz , "onListPlayerAttributeValues" , "(B)V");
+ env->GetMethodID(clazz , "onListPlayerAttributeValues" , "(B[B)V");
method_getElementAttr =
- env->GetMethodID(clazz, "getElementAttr", "(B[I)V");
+ env->GetMethodID(clazz, "getElementAttr", "(B[I[B)V");
method_setPlayerAppSetting =
- env->GetMethodID(clazz, "setPlayerAppSetting","(B[B[B)V");
+ env->GetMethodID(clazz, "setPlayerAppSetting","(B[B[B[B)V");
method_getplayerattribute_text =
- env->GetMethodID(clazz, "getplayerattribute_text" , "(B[B)V");
+ env->GetMethodID(clazz, "getplayerattribute_text" , "(B[B[B)V");
method_getplayervalue_text =
- env->GetMethodID(clazz, "getplayervalue_text" , "(BB[B)V");
+ env->GetMethodID(clazz, "getplayervalue_text" , "(BB[B[B)V");
method_registerNotification =
- env->GetMethodID(clazz, "registerNotification", "(II)V");
+ env->GetMethodID(clazz, "registerNotification", "(II[B)V");
method_onGetPlayerAttributeValues =
- env->GetMethodID(clazz, "onGetPlayerAttributeValues", "(B[I)V");
+ env->GetMethodID(clazz, "onGetPlayerAttributeValues", "(B[I[B)V");
method_volumeChangeCallback =
- env->GetMethodID(clazz, "volumeChangeCallback", "(II)V");
+ env->GetMethodID(clazz, "volumeChangeCallback", "(II[B)V");
method_handlePassthroughCmd =
- env->GetMethodID(clazz, "handlePassthroughCmd", "(II)V");
+ env->GetMethodID(clazz, "handlePassthroughCmd", "(II[B)V");
//setAddressedPlayer: attributes to pass: Player ID
method_setAddressedPlayer =
- env->GetMethodID(clazz, "setAddressedPlayer", "(I)V");
+ env->GetMethodID(clazz, "setAddressedPlayer", "(I[B)V");
//getFolderItems: attributes to pass: Scope, Start, End, Attr Cnt
method_getFolderItems =
- env->GetMethodID(clazz, "getFolderItems", "(BJJII[I)V");
+ env->GetMethodID(clazz, "getFolderItems", "(BJJII[I[B)V");
method_setBrowsedPlayer =
- env->GetMethodID(clazz, "setBrowsedPlayer", "(I)V");
+ env->GetMethodID(clazz, "setBrowsedPlayer", "(I[B)V");
method_changePath =
- env->GetMethodID(clazz, "changePath", "(BJ)V");
+ env->GetMethodID(clazz, "changePath", "(BJ[B)V");
method_playItem =
- env->GetMethodID(clazz, "playItem", "(BJ)V");
+ env->GetMethodID(clazz, "playItem", "(BJ[B)V");
method_getItemAttr =
- env->GetMethodID(clazz, "getItemAttr", "(BJB[I)V");
+ env->GetMethodID(clazz, "getItemAttr", "(BJB[I[B)V");
+ method_onConnectionStateChanged =
+ env->GetMethodID(clazz, "onConnectionStateChanged", "(Z[B)V");
ALOGI("%s: succeeds", __FUNCTION__);
}
-static void initNative(JNIEnv *env, jobject object) {
+static void initNative(JNIEnv *env, jobject object,
+ jint maxAvrcpConnections) {
const bt_interface_t* btInf;
bt_status_t status;
@@ -535,10 +747,10 @@ static void initNative(JNIEnv *env, jobject object) {
return;
}
- if (sBluetoothAvrcpInterface !=NULL) {
+ if (sBluetoothMultiAvrcpInterface !=NULL) {
ALOGW("Cleaning up Avrcp Interface before initializing...");
- sBluetoothAvrcpInterface->cleanup();
- sBluetoothAvrcpInterface = NULL;
+ sBluetoothMultiAvrcpInterface->cleanup();
+ sBluetoothMultiAvrcpInterface = NULL;
}
if (mCallbacksObj != NULL) {
@@ -547,16 +759,17 @@ static void initNative(JNIEnv *env, jobject object) {
mCallbacksObj = NULL;
}
- if ( (sBluetoothAvrcpInterface = (btrc_interface_t *)
+ if ( (sBluetoothMultiAvrcpInterface = (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)) !=
+ if ((status = sBluetoothMultiAvrcpInterface->init(&sBluetoothAvrcpCallbacks,
+ maxAvrcpConnections)) !=
BT_STATUS_SUCCESS) {
ALOGE("Failed to initialize Bluetooth Avrcp, status: %d", status);
- sBluetoothAvrcpInterface = NULL;
+ sBluetoothMultiAvrcpInterface = NULL;
return;
}
@@ -571,9 +784,9 @@ static void cleanupNative(JNIEnv *env, jobject object) {
return;
}
- if (sBluetoothAvrcpInterface !=NULL) {
- sBluetoothAvrcpInterface->cleanup();
- sBluetoothAvrcpInterface = NULL;
+ if (sBluetoothMultiAvrcpInterface !=NULL) {
+ sBluetoothMultiAvrcpInterface->cleanup();
+ sBluetoothMultiAvrcpInterface = NULL;
}
if (mCallbacksObj != NULL) {
@@ -583,28 +796,44 @@ static void cleanupNative(JNIEnv *env, jobject object) {
}
static jboolean getPlayStatusRspNative(JNIEnv *env, jobject object, jint playStatus,
- jint songLen, jint songPos) {
+ jint songLen, jint songPos, jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
- if ((status = sBluetoothAvrcpInterface->get_play_status_rsp((btrc_play_status_t)playStatus,
- songLen, songPos)) != BT_STATUS_SUCCESS) {
- ALOGE("Failed get_play_status_rsp, status: %d", status);
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
}
+ if ((status = sBluetoothMultiAvrcpInterface->get_play_status_rsp((btrc_play_status_t)playStatus,
+ songLen, songPos,
+ (bt_bdaddr_t *)addr)) != 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 getListPlayerappAttrRspNative(JNIEnv *env ,jobject object , jbyte numAttr,
- jbyteArray attrIds ) {
+ jbyteArray attrIds , jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
btrc_player_attr_t *pAttrs = NULL;
int i;
jbyte *attr;
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+
if( numAttr > BTRC_MAX_APP_ATTR_SIZE) {
ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
return JNI_FALSE;
@@ -630,24 +859,28 @@ static jboolean getListPlayerappAttrRspNative(JNIEnv *env ,jobject object , jbyt
return JNI_FALSE;
}
//Call Stack Method
- if ((status = sBluetoothAvrcpInterface->list_player_app_attr_rsp(numAttr, pAttrs)) !=
- BT_STATUS_SUCCESS) {
- ALOGE("Failed getelementattrrsp, status: %d", status);
+ if ((status = sBluetoothMultiAvrcpInterface->list_player_app_attr_rsp(numAttr, pAttrs,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
+ ALOGE("Failed list_player_app_attr_rsp, status: %d", status);
}
delete[] pAttrs;
env->ReleaseByteArrayElements(attrIds, attr, 0);
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean getPlayerAppValueRspNative(JNIEnv *env ,jobject object , jbyte numvalue,
- jbyteArray value)
+ jbyteArray value ,jbyteArray address)
{
bt_status_t status;
+ jbyte *addr;
uint8_t *pAttrs = NULL;
int i;
jbyte *attr;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
if( numvalue > BTRC_MAX_APP_ATTR_SIZE) {
ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
return JNI_FALSE;
@@ -658,6 +891,13 @@ static jboolean getPlayerAppValueRspNative(JNIEnv *env ,jobject object , jbyte n
return JNI_FALSE;
}
attr = env->GetByteArrayElements(value, NULL);
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+
if (!attr) {
delete[] pAttrs;
jniThrowIOException(env, EINVAL);
@@ -671,22 +911,31 @@ static jboolean getPlayerAppValueRspNative(JNIEnv *env ,jobject object , jbyte n
env->ReleaseByteArrayElements(value, attr, 0);
return JNI_FALSE;
}
- if ((status = sBluetoothAvrcpInterface->list_player_app_value_rsp(numvalue, pAttrs)) !=
- BT_STATUS_SUCCESS) {
- ALOGE("Failed get_element_attr_rsp, status: %d", status);
+ if ((status = sBluetoothMultiAvrcpInterface->list_player_app_value_rsp(numvalue, pAttrs,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
+ ALOGE("Failed list_player_app_value_rsp, status: %d", status);
}
delete[] pAttrs;
env->ReleaseByteArrayElements(value, attr, 0);
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean SendCurrentPlayerValueRspNative(JNIEnv *env, jobject object ,
- jbyte numattr ,jbyteArray value) {
+ jbyte numattr ,jbyteArray value ,jbyteArray address) {
btrc_player_settings_t *pAttrs = NULL ;
bt_status_t status;
+ jbyte *addr;
int i;
jbyte *attr;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
if( numattr > BTRC_MAX_APP_ATTR_SIZE || numattr == 0) {
ALOGE("SendCurrentPlayerValueRspNative: number of attributes exceed maximum");
return JNI_FALSE;
@@ -708,40 +957,60 @@ static jboolean SendCurrentPlayerValueRspNative(JNIEnv *env, jobject object ,
pAttrs->attr_ids[i/2] = attr[i];
pAttrs->attr_values[i/2] = attr[i+1];
}
- if ((status = sBluetoothAvrcpInterface->get_player_app_value_rsp(pAttrs)) !=
- BT_STATUS_SUCCESS) {
- ALOGE("Failed get_element_attr_rsp, status: %d", status);
+ if ((status = sBluetoothMultiAvrcpInterface->get_player_app_value_rsp(pAttrs,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
+ ALOGE("Failed get_player_app_value_rsp, status: %d", status);
}
delete pAttrs;
env->ReleaseByteArrayElements(value, attr, 0);
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
//JNI Method called to Respond to PDU 0x14
-static jboolean SendSetPlayerAppRspNative(JNIEnv *env, jobject object , jint attr_status)
+static jboolean SendSetPlayerAppRspNative(JNIEnv *env, jobject object,
+ jint attr_status, jbyteArray address)
{
bt_status_t status;
+ jbyte *addr;
btrc_status_t player_rsp = (btrc_status_t) attr_status;
- if ((status = sBluetoothAvrcpInterface->set_player_app_value_rsp(player_rsp)) !=
- BT_STATUS_SUCCESS) {
- ALOGE("Failed get_element_attr_rsp, status: %d", status);
+
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
}
+ if ((status = sBluetoothMultiAvrcpInterface->set_player_app_value_rsp(player_rsp,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
+ ALOGE("Failed set_player_app_value_rsp, status: %d", status);
+ }
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
//JNI Method Called to Respond to PDU 0x15
static jboolean sendSettingsTextRspNative(JNIEnv *env, jobject object, jint num_attr,
- jbyteArray attr,jint length , jobjectArray textArray ) {
+ jbyteArray attr,jint length , jobjectArray textArray,
+ jbyteArray address) {
btrc_player_setting_text_t *pAttrs = NULL;
bt_status_t status;
+ jbyte *addr;
int i;
jstring text;
const char* textStr;
jbyte *arr ;
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
if (num_attr > BTRC_MAX_ELEM_ATTR_SIZE) {
ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
return JNI_FALSE;
@@ -778,27 +1047,36 @@ static jboolean sendSettingsTextRspNative(JNIEnv *env, jobject object, jint num_
env->DeleteLocalRef(text);
}
//Call Stack Methos to Respond PDU 0x16
- if ((status = sBluetoothAvrcpInterface->get_player_app_attr_text_rsp(num_attr, pAttrs))
- != BT_STATUS_SUCCESS) {
- ALOGE("Failed get_element_attr_rsp, status: %d", status);
+ if ((status = sBluetoothMultiAvrcpInterface->get_player_app_attr_text_rsp(num_attr, pAttrs,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
+ ALOGE("Failed get_player_app_attr_text_rsp, status: %d", status);
}
delete[] pAttrs;
env->ReleaseByteArrayElements(attr, arr, 0);
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
//JNI Method Called to respond to PDU 0x16
static jboolean sendValueTextRspNative(JNIEnv *env, jobject object, jint num_attr,
- jbyteArray attr, jint length , jobjectArray textArray ) {
+ jbyteArray attr, jint length , jobjectArray textArray,
+ jbyteArray address) {
btrc_player_setting_text_t *pAttrs = NULL;
bt_status_t status;
+ jbyte *addr;
int i;
jstring text ;
const char* textStr;
jbyte *arr ;
//ALOGE("sendValueTextRspNative");
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
if (num_attr > BTRC_MAX_ELEM_ATTR_SIZE) {
ALOGE("sendValueTextRspNative: number of attributes exceed maximum");
return JNI_FALSE;
@@ -834,26 +1112,34 @@ static jboolean sendValueTextRspNative(JNIEnv *env, jobject object, jint num_att
env->DeleteLocalRef(text);
}
//Call Stack Method to Respond to PDU 0x16
- if ((status = sBluetoothAvrcpInterface->get_player_app_value_text_rsp(num_attr, pAttrs))
- != BT_STATUS_SUCCESS) {
- ALOGE("Failed get_element_attr_rsp, status: %d", status);
+ if ((status = sBluetoothMultiAvrcpInterface->get_player_app_value_text_rsp(num_attr, pAttrs,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
+ ALOGE("Failed get_player_app_value_text_rsp, status: %d", status);
}
delete[] pAttrs;
env->ReleaseByteArrayElements(attr, arr, 0);
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean getElementAttrRspNative(JNIEnv *env, jobject object, jbyte numAttr,
- jintArray attrIds, jobjectArray textArray) {
+ jintArray attrIds, jobjectArray textArray,
+ jbyteArray address) {
jint *attr;
bt_status_t status;
+ jbyte *addr;
jstring text;
int i;
btrc_element_attr_val_t *pAttrs = NULL;
const char* textStr;
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ 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;
@@ -899,23 +1185,33 @@ static jboolean sendValueTextRspNative(JNIEnv *env, jobject object, jint num_att
return JNI_FALSE;
}
- if ((status = sBluetoothAvrcpInterface->get_element_attr_rsp(numAttr, pAttrs)) !=
- BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->get_element_attr_rsp(numAttr, pAttrs,
+ (bt_bdaddr_t *)addr)) != 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 registerNotificationPlayerAppRspNative(JNIEnv *env, jobject object ,jint type,
- jbyte numattr ,jbyteArray value) {
+ jbyte numattr ,jbyteArray value ,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
int i;
jbyte *attr;
btrc_register_notification_t *param= NULL;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
if( numattr > BTRC_MAX_APP_ATTR_SIZE || numattr == 0) {
ALOGE("registerNotificationPlayerAppRspNative: number of attributes exceed maximum");
return JNI_FALSE;
@@ -939,43 +1235,63 @@ static jboolean registerNotificationPlayerAppRspNative(JNIEnv *env, jobject obje
param->player_setting.attr_values[i/2] = attr[i+1];
}
//Call Stack Method
- if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_APP_SETTINGS_CHANGED,
- (btrc_notification_type_t)type,param)) !=
- BT_STATUS_SUCCESS) {
- ALOGE("Failed get_element_attr_rsp, status: %d", status);
+ if ((status =
+ sBluetoothMultiAvrcpInterface->register_notification_rsp(
+ BTRC_EVT_APP_SETTINGS_CHANGED,
+ (btrc_notification_type_t)type,param,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
+ ALOGE("Failed register_notification_rsp, status: %d", status);
}
delete param;
env->ReleaseByteArrayElements(value, 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) {
+ jint type, jint playStatus,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
btrc_register_notification_t param;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ 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) {
+ if ((status =
+ sBluetoothMultiAvrcpInterface->register_notification_rsp(
+ BTRC_EVT_PLAY_STATUS_CHANGED,
+ (btrc_notification_type_t)type, &param, (bt_bdaddr_t *)addr)) !=
+ BT_STATUS_SUCCESS) {
ALOGE("Failed register_notification_rsp play status, status: %d", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspTrackChangeNative(JNIEnv *env, jobject object,
- jint type, jbyteArray track) {
+ jint type, jbyteArray track,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
btrc_register_notification_t param;
jbyte *trk;
int i;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
trk = env->GetByteArrayElements(track, NULL);
if (!trk) {
jniThrowIOException(env, EINVAL);
@@ -986,102 +1302,149 @@ static jboolean registerNotificationRspTrackChangeNative(JNIEnv *env, jobject ob
param.track[i] = trk[i];
}
- if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_TRACK_CHANGE,
- (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->register_notification_rsp(BTRC_EVT_TRACK_CHANGE,
+ (btrc_notification_type_t)type, &param, (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed register_notification_rsp track change, status: %d", status);
}
env->ReleaseByteArrayElements(track, trk, 0);
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspPlayPosNative(JNIEnv *env, jobject object,
- jint type, jint playPos) {
+ jint type, jint playPos,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
+
btrc_register_notification_t param;
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ 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) {
+ if ((status = sBluetoothMultiAvrcpInterface->register_notification_rsp(
+ BTRC_EVT_PLAY_POS_CHANGED,
+ (btrc_notification_type_t)type, &param, (bt_bdaddr_t *)addr)) !=
+ BT_STATUS_SUCCESS) {
ALOGE("Failed register_notification_rsp play position, status: %d", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume) {
+static jboolean setVolumeNative(JNIEnv *env, jobject object, jint volume,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
//TODO: delete test code
ALOGI("%s: jint: %d, uint8_t: %u", __FUNCTION__, volume, (uint8_t) volume);
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
- if ((status = sBluetoothAvrcpInterface->set_volume((uint8_t)volume)) != BT_STATUS_SUCCESS) {
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+ if ((status = sBluetoothMultiAvrcpInterface->set_volume((uint8_t)volume,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed set_volume, status: %d", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspAddressedPlayerChangedNative (JNIEnv *env,
- jobject object, jint type, jint playerId) {
+ jobject object, jint type,
+ jint playerId,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
btrc_register_notification_t param;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
ALOGI("playerId: %d", playerId);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
param.player_id = (uint16_t)playerId;
- if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_ADDRESSED_PLAYER_CHANGED,
- (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->register_notification_rsp(
+ BTRC_EVT_ADDRESSED_PLAYER_CHANGED, (btrc_notification_type_t)type,
+ &param, (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed registerNotificationRspAddressedPlayerChangedNative, status: %d", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspAvailablePlayersChangedNative (JNIEnv *env,
- jobject object, jint type) {
+ jobject object, jint type,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
btrc_register_notification_t param;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
- if ((status = sBluetoothAvrcpInterface->register_notification_rsp(BTRC_EVT_AVAILABLE_PLAYERS_CHANGED,
- (btrc_notification_type_t)type, &param)) != BT_STATUS_SUCCESS) {
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+ if ((status = sBluetoothMultiAvrcpInterface->register_notification_rsp(
+ BTRC_EVT_AVAILABLE_PLAYERS_CHANGED, (btrc_notification_type_t)type,
+ &param, (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed registerNotificationRspAvailablePlayersChangedNative, status: %d", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean registerNotificationRspNowPlayingContentChangedNative(JNIEnv *env,
- jobject object, jint type) {
+ jobject object, jint type,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
btrc_register_notification_t param;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
- if ((status = sBluetoothAvrcpInterface->register_notification_rsp(
- BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED, (btrc_notification_type_t)type, &param)) !=
- BT_STATUS_SUCCESS) {
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+ if ((status = sBluetoothMultiAvrcpInterface->register_notification_rsp(
+ BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED, (btrc_notification_type_t)type, &param,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed registerNotificationRspNowPlayingContentChangedNative, status: %d", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean getFolderItemsRspNative(JNIEnv *env, jobject object, jbyte statusCode,
jlong numItems, jintArray itemType, jlongArray uid, jintArray type,
jbyteArray playable, jobjectArray displayName, jbyteArray numAtt,
- jobjectArray attValues, jintArray attIds) {
+ jobjectArray attValues, jintArray attIds , jbyteArray address) {
bt_status_t status = BT_STATUS_SUCCESS;
+ jbyte *addr;
btrc_folder_list_entries_t param;
int32_t *itemTypeElements;
int64_t *uidElements;
@@ -1097,9 +1460,14 @@ static jboolean getFolderItemsRspNative(JNIEnv *env, jobject object, jbyte statu
jsize utfStringLength = 0;
int num_attr;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
param.status = statusCode;
param.uid_counter = 0;
param.item_count = numItems;
@@ -1175,9 +1543,9 @@ static jboolean getFolderItemsRspNative(JNIEnv *env, jobject object, jbyte statu
}
param.p_item_list[count].u.folder.name.charset_id = BTRC_CHARSET_UTF8;
param.p_item_list[count].u.folder.name.str_len = utfStringLength;
- param.p_item_list[count].u.folder.name.p_str = new uint8_t[utfStringLength];
+ param.p_item_list[count].u.folder.name.p_str = new uint8_t[utfStringLength + 1];
strlcpy((char *)param.p_item_list[count].u.folder.name.p_str, textStr,
- utfStringLength);
+ utfStringLength + 1);
env->ReleaseStringUTFChars(text, textStr);
env->DeleteLocalRef(text);
} else if (itemTypeElements[count] == BTRC_TYPE_MEDIA_ELEMENT) {
@@ -1207,9 +1575,9 @@ static jboolean getFolderItemsRspNative(JNIEnv *env, jobject object, jbyte statu
}
param.p_item_list[count].u.media.name.charset_id = BTRC_CHARSET_UTF8;
param.p_item_list[count].u.media.name.str_len = utfStringLength;
- param.p_item_list[count].u.media.name.p_str = new uint8_t[utfStringLength];
+ param.p_item_list[count].u.media.name.p_str = new uint8_t[utfStringLength + 1];
strlcpy((char *)param.p_item_list[count].u.media.name.p_str, textStr,
- utfStringLength);
+ utfStringLength + 1);
env->ReleaseStringUTFChars(text, textStr);
env->DeleteLocalRef(text);
ALOGI("getFolderItemsRspNative: numAttr: %d", numAttElements[count]);
@@ -1245,9 +1613,9 @@ static jboolean getFolderItemsRspNative(JNIEnv *env, jobject object, jbyte statu
ALOGI("getFolderItemsRspNative: Attr Length: %d",
param.p_item_list[count].u.media.p_attr_list[num_attr].name.str_len);
param.p_item_list[count].u.media.p_attr_list[num_attr].name.p_str =
- new uint8_t[utfStringLength];
+ new uint8_t[utfStringLength + 1];
strlcpy((char *)param.p_item_list[count].u.media.p_attr_list[num_attr].
- name.p_str, textStr, utfStringLength);
+ name.p_str, textStr, utfStringLength + 1);
num_attr++;
env->ReleaseStringUTFChars(text, textStr);
env->DeleteLocalRef(text);
@@ -1258,24 +1626,29 @@ static jboolean getFolderItemsRspNative(JNIEnv *env, jobject object, jbyte statu
}
}
- if ((status = sBluetoothAvrcpInterface->get_folder_items_rsp(&param)) != BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->get_folder_items_rsp(&param,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed get_folder_items_rsp, status: %u", status);
}
- env->ReleaseIntArrayElements(itemType, itemTypeElements, 0);
- env->ReleaseLongArrayElements(uid, uidElements, 0);
- env->ReleaseIntArrayElements(type, typeElements, 0);
- env->ReleaseByteArrayElements(playable, playableElements, 0);
- env->ReleaseByteArrayElements(numAtt, numAttElements, 0);
- env->ReleaseIntArrayElements(attIds, attIdsElements, 0);
+ if (numItems > 0) {
+ env->ReleaseIntArrayElements(itemType, itemTypeElements, 0);
+ env->ReleaseLongArrayElements(uid, uidElements, 0);
+ env->ReleaseIntArrayElements(type, typeElements, 0);
+ env->ReleaseByteArrayElements(playable, playableElements, 0);
+ env->ReleaseByteArrayElements(numAtt, numAttElements, 0);
+ env->ReleaseIntArrayElements(attIds, attIdsElements, 0);
+ }
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
// MediaPlayerItems are populated as byte stream from the apps
static jboolean getMediaPlayerListRspNative(JNIEnv *env, jobject object, jbyte statusCode,
- jint uidCounter, jint itemCount, jbyteArray folderItems, jintArray folderItemLengths) {
+ jint uidCounter, jint itemCount, jbyteArray folderItems,
+ jintArray folderItemLengths, jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
int8_t *folderElements;
int32_t *folderElementLengths;
int32_t count = 0;
@@ -1285,9 +1658,14 @@ static jboolean getMediaPlayerListRspNative(JNIEnv *env, jobject object, jbyte s
int32_t checkLength = 0;
btrc_folder_list_entries_t param;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
folderElements = env->GetByteArrayElements(folderItems, NULL);
if (!folderElements) {
jniThrowIOException(env, EINVAL);
@@ -1367,33 +1745,43 @@ static jboolean getMediaPlayerListRspNative(JNIEnv *env, jobject object, jbyte s
}
}
- if ((status = sBluetoothAvrcpInterface->get_folder_items_rsp(&param)) !=
- BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->get_folder_items_rsp(&param,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed getMediaPlayerListRspNative, status: %u", status);
}
env->ReleaseByteArrayElements(folderItems, folderElements, 0);
env->ReleaseIntArrayElements(folderItemLengths, folderElementLengths, 0);
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean setAdressedPlayerRspNative(JNIEnv *env, jobject object, jbyte statusCode) {
+static jboolean setAdressedPlayerRspNative(JNIEnv *env, jobject object, jbyte statusCode,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
- if ((status = sBluetoothAvrcpInterface->set_addressed_player_rsp((btrc_status_t)statusCode)) != BT_STATUS_SUCCESS) {
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+ if ((status = sBluetoothMultiAvrcpInterface->set_addressed_player_rsp((btrc_status_t)statusCode,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed setAdressedPlayerRspNative, status: %d", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
static jboolean getItemAttrRspNative(JNIEnv *env, jobject object, jbyte numAttr,
- jintArray attrIds, jobjectArray textArray) {
+ jintArray attrIds, jobjectArray textArray,
+ jbyteArray address) {
jint *attr;
+ jbyte *addr;
bt_status_t status;
jstring text;
int i;
@@ -1401,8 +1789,13 @@ static jboolean getItemAttrRspNative(JNIEnv *env, jobject object, jbyte numAttr,
const char* textStr;
jsize utfStringLength = 0;
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
ALOGE("get_item_attr_rsp: number of attributes exceed maximum");
return JNI_FALSE;
@@ -1444,7 +1837,7 @@ static jboolean getItemAttrRspNative(JNIEnv *env, jobject object, jbyte numAttr,
strlcpy((char *)pAttrs[i].text, textStr, BTRC_MAX_ATTR_STR_LEN-1);
pAttrs[i].text[BTRC_MAX_ATTR_STR_LEN-1] = 0;
} else {
- strlcpy((char *)pAttrs[i].text, textStr, utfStringLength);
+ strlcpy((char *)pAttrs[i].text, textStr, utfStringLength + 1);
}
env->ReleaseStringUTFChars(text, textStr);
env->DeleteLocalRef(text);
@@ -1456,21 +1849,24 @@ static jboolean getItemAttrRspNative(JNIEnv *env, jobject object, jbyte numAttr,
return JNI_FALSE;
}
- if ((status = sBluetoothAvrcpInterface->get_item_attr_rsp(numAttr, pAttrs)) !=
- BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->get_item_attr_rsp(numAttr, pAttrs,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed get_item_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 setBrowsedPlayerRspNative(JNIEnv *env, jobject object,
- jbyte statusCode, jint uidCounter,
- jint itemCount, jint folderDepth,
- jint charId, jobjectArray folderNames) {
+ jbyte statusCode, jint uidCounter,
+ jint itemCount, jint folderDepth,
+ jint charId, jobjectArray folderNames,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
int32_t count = 0;
jstring text;
const char* textStr;
@@ -1478,9 +1874,14 @@ static jboolean setBrowsedPlayerRspNative(JNIEnv *env, jobject object,
btrc_set_browsed_player_rsp_t param;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
param.status = statusCode;
param.uid_counter = uidCounter;
param.num_items = itemCount;
@@ -1513,95 +1914,135 @@ static jboolean setBrowsedPlayerRspNative(JNIEnv *env, jobject object,
}
param.p_folders[count].str_len = utfStringLength;
- param.p_folders[count].p_str = new uint8_t[utfStringLength];
- strlcpy((char *)param.p_folders[count].p_str, textStr, utfStringLength);
+ param.p_folders[count].p_str = new uint8_t[utfStringLength + 1];
+ strlcpy((char *)param.p_folders[count].p_str, textStr, utfStringLength + 1);
env->ReleaseStringUTFChars(text, textStr);
env->DeleteLocalRef(text);
}
- if ((status = sBluetoothAvrcpInterface->set_browsed_player_rsp(&param)) != BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->set_browsed_player_rsp(&param,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed setBrowsedPlayerRspNative, status: %u", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean changePathRspNative(JNIEnv *env, jobject object, jint errStatus, jlong itemCount) {
+static jboolean changePathRspNative(JNIEnv *env, jobject object, jint errStatus, jlong itemCount,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
ALOGI("status: %d, itemCount: %l", errStatus, itemCount);
- if ((status = sBluetoothAvrcpInterface->change_path_rsp((uint8_t)errStatus,
- (uint32_t)itemCount))!= BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->change_path_rsp((uint8_t)errStatus,
+ (uint32_t)itemCount,
+ (bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
ALOGE("Failed sending change path response, status: %d", status);
}
-
+ env->ReleaseByteArrayElements(address, addr, 0);
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean playItemRspNative(JNIEnv *env, jobject object, jint errStatus) {
+static jboolean playItemRspNative(JNIEnv *env, jobject object, jint errStatus,
+ jbyteArray address) {
bt_status_t status;
+ jbyte *addr;
- if (!sBluetoothAvrcpInterface) return JNI_FALSE;
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
- ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
ALOGI("status: %d", errStatus);
- if ((status = sBluetoothAvrcpInterface->play_item_rsp((uint8_t)errStatus))!= BT_STATUS_SUCCESS) {
+ if ((status = sBluetoothMultiAvrcpInterface->play_item_rsp((uint8_t)errStatus,
+ (bt_bdaddr_t *)addr))!= BT_STATUS_SUCCESS) {
ALOGE("Failed sending play item response, status: %d", status);
}
+ env->ReleaseByteArrayElements(address, addr, 0);
+ return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean isDeviceActiveInHandOffNative(JNIEnv *env, jobject object, jbyteArray address) {
+ bt_status_t status = BT_STATUS_SUCCESS;
+ jbyte *addr;
+
+ if (!sBluetoothMultiAvrcpInterface) return JNI_FALSE;
+ addr = env->GetByteArrayElements(address, NULL);
+ if (!addr) {
+ jniThrowIOException(env, EINVAL);
+ return JNI_FALSE;
+ }
+ ALOGI("%s: sBluetoothMultiAvrcpInterface: %p", __FUNCTION__, sBluetoothMultiAvrcpInterface);
+
+ status = sBluetoothMultiAvrcpInterface->is_device_active_in_handoff((bt_bdaddr_t *)addr);
+
+ ALOGI("isDeviceActiveInHandOffNative: 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},
+ {"initNative", "(I)V", (void *) initNative},
{"cleanupNative", "()V", (void *) cleanupNative},
- {"getPlayStatusRspNative", "(III)Z", (void *) getPlayStatusRspNative},
- {"getElementAttrRspNative", "(B[I[Ljava/lang/String;)Z", (void *) getElementAttrRspNative},
- {"getListPlayerappAttrRspNative", "(B[B)Z", (void *) getListPlayerappAttrRspNative},
- {"getPlayerAppValueRspNative", "(B[B)Z", (void *) getPlayerAppValueRspNative},
- {"registerNotificationRspPlayStatusNative", "(II)Z",
+ {"getPlayStatusRspNative", "(III[B)Z", (void *) getPlayStatusRspNative},
+ {"getElementAttrRspNative", "(B[I[Ljava/lang/String;[B)Z", (void *) getElementAttrRspNative},
+ {"getListPlayerappAttrRspNative", "(B[B[B)Z", (void *) getListPlayerappAttrRspNative},
+ {"getPlayerAppValueRspNative", "(B[B[B)Z", (void *) getPlayerAppValueRspNative},
+ {"registerNotificationRspPlayStatusNative", "(II[B)Z",
(void *) registerNotificationRspPlayStatusNative},
- {"SendCurrentPlayerValueRspNative", "(B[B)Z",
+ {"SendCurrentPlayerValueRspNative", "(B[B[B)Z",
(void *) SendCurrentPlayerValueRspNative},
- {"registerNotificationPlayerAppRspNative", "(IB[B)Z",
+ {"registerNotificationPlayerAppRspNative", "(IB[B[B)Z",
(void *) registerNotificationPlayerAppRspNative},
- {"registerNotificationRspTrackChangeNative", "(I[B)Z",
+ {"registerNotificationRspTrackChangeNative", "(I[B[B)Z",
(void *) registerNotificationRspTrackChangeNative},
- {"SendSetPlayerAppRspNative", "(I)Z",
+ {"SendSetPlayerAppRspNative", "(I[B)Z",
(void *) SendSetPlayerAppRspNative},
- {"sendSettingsTextRspNative" , "(I[BI[Ljava/lang/String;)Z",
+ {"sendSettingsTextRspNative" , "(I[BI[Ljava/lang/String;[B)Z",
(void *) sendSettingsTextRspNative},
- {"sendValueTextRspNative" , "(I[BI[Ljava/lang/String;)Z",
+ {"sendValueTextRspNative" , "(I[BI[Ljava/lang/String;[B)Z",
(void *) sendValueTextRspNative},
- {"registerNotificationRspPlayPosNative", "(II)Z",
+ {"registerNotificationRspPlayPosNative", "(II[B)Z",
(void *) registerNotificationRspPlayPosNative},
- {"setVolumeNative", "(I)Z",
+ {"setVolumeNative", "(I[B)Z",
(void *) setVolumeNative},
- {"setAdressedPlayerRspNative", "(B)Z",
+ {"setAdressedPlayerRspNative", "(B[B)Z",
(void *) setAdressedPlayerRspNative},
- {"getMediaPlayerListRspNative", "(BII[B[I)Z",
+ {"getMediaPlayerListRspNative", "(BII[B[I[B)Z",
(void *) getMediaPlayerListRspNative},
- {"registerNotificationRspAddressedPlayerChangedNative", "(II)Z",
+ {"registerNotificationRspAddressedPlayerChangedNative", "(II[B)Z",
(void *) registerNotificationRspAddressedPlayerChangedNative},
- {"registerNotificationRspAvailablePlayersChangedNative", "(I)Z",
+ {"registerNotificationRspAvailablePlayersChangedNative", "(I[B)Z",
(void *) registerNotificationRspAvailablePlayersChangedNative},
- {"registerNotificationRspNowPlayingContentChangedNative", "(I)Z",
+ {"registerNotificationRspNowPlayingContentChangedNative", "(I[B)Z",
(void *) registerNotificationRspNowPlayingContentChangedNative},
- {"setBrowsedPlayerRspNative", "(BIIII[Ljava/lang/String;)Z",
+ {"setBrowsedPlayerRspNative", "(BIIII[Ljava/lang/String;[B)Z",
(void *) setBrowsedPlayerRspNative},
- {"changePathRspNative", "(IJ)Z", (void *) changePathRspNative},
- {"playItemRspNative", "(I)Z", (void *) playItemRspNative},
- {"getItemAttrRspNative", "(B[I[Ljava/lang/String;)Z", (void *) getItemAttrRspNative},
- {"getFolderItemsRspNative", "(BJ[I[J[I[B[Ljava/lang/String;[B[Ljava/lang/String;[I)Z",
+ {"changePathRspNative", "(IJ[B)Z", (void *) changePathRspNative},
+ {"playItemRspNative", "(I[B)Z", (void *) playItemRspNative},
+ {"getItemAttrRspNative", "(B[I[Ljava/lang/String;[B)Z", (void *) getItemAttrRspNative},
+ {"getFolderItemsRspNative", "(BJ[I[J[I[B[Ljava/lang/String;[B[Ljava/lang/String;[I[B)Z",
(void *) getFolderItemsRspNative},
+ {"isDeviceActiveInHandOffNative", "([B)Z", (void *) isDeviceActiveInHandOffNative},
};
int register_com_android_bluetooth_avrcp(JNIEnv* env)
diff --git a/src/com/android/bluetooth/a2dp/A2dpService.java b/src/com/android/bluetooth/a2dp/A2dpService.java
index a0d1c30f1..094766b01 100755
--- a/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,8 +25,10 @@ import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothA2dp;
import android.content.Context;
import android.content.Intent;
+import android.media.AudioManager;
import android.os.ParcelUuid;
import android.provider.Settings;
+import android.os.SystemProperties;
import android.util.Log;
import com.android.bluetooth.avrcp.Avrcp;
import com.android.bluetooth.btservice.ProfileService;
@@ -43,6 +48,7 @@ public class A2dpService extends ProfileService {
private A2dpStateMachine mStateMachine;
private Avrcp mAvrcp;
+ private AudioManager mAudioManager;
private static A2dpService sAd2dpService;
static final ParcelUuid[] A2DP_SOURCE_UUID = {
BluetoothUuid.AudioSource
@@ -61,9 +67,28 @@ public class A2dpService extends ProfileService {
}
protected boolean start() {
- mAvrcp = Avrcp.make(this);
- mStateMachine = A2dpStateMachine.make(this, this);
+ int maxConnections = 1;
+ int multiCastState = 0;
+ int maxA2dpConnection =
+ SystemProperties.getInt("persist.bt.max.a2dp.connections", 1);
+ int a2dpMultiCastState =
+ SystemProperties.getInt("persist.bt.enable.multicast", 0);
+ if (a2dpMultiCastState == 1)
+ multiCastState = a2dpMultiCastState;
+ if (maxA2dpConnection == 2)
+ maxConnections = maxA2dpConnection;
+ // enable soft hands-off also when multicast is enabled.
+ if (multiCastState == 1 && maxConnections != 2) {
+ Log.i(TAG,"Enable soft handsoff as multicast is enabled");
+ maxConnections = 2;
+ }
+ log( "maxA2dpConnections = " + maxConnections);
+ log( "multiCastState = " + multiCastState);
+ mAvrcp = Avrcp.make(this, this, maxConnections);
+ mStateMachine = A2dpStateMachine.make(this, this,
+ maxConnections, multiCastState);
setA2dpService(this);
+ mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
return true;
}
@@ -209,8 +234,43 @@ public class A2dpService extends ProfileService {
mAvrcp.setAbsoluteVolume(volume);
}
- public void setAvrcpAudioState(int state) {
- mAvrcp.setA2dpAudioState(state);
+ public void setAvrcpAudioState(int state, BluetoothDevice device) {
+ mAvrcp.setA2dpAudioState(state, device);
+ }
+
+ public List<BluetoothDevice> getA2dpPlayingDevice() {
+ return mStateMachine.getPlayingDevice();
+ }
+
+ public boolean isMulticastEnabled() {
+ return mStateMachine.isMulticastEnabled();
+ }
+
+ public boolean isMulticastFeatureEnabled() {
+ return mStateMachine.isMulticastFeatureEnabled();
+ }
+
+ // return status of multicast,needed for blocking outgoing connections
+ public boolean isMulticastOngoing(BluetoothDevice device) {
+
+ Log.i(TAG,"audio isMusicActive is " + mAudioManager.isMusicActive());
+ // we should never land is case where playing device size is bigger
+ // than 2 still have safe check.
+ if (device == null) {
+ if ((getA2dpPlayingDevice().size() >= 2) &&
+ (mAudioManager.isMusicActive())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ if ((getA2dpPlayingDevice().size() >= 2) &&
+ mAudioManager.isMusicActive() &&
+ !(getA2dpPlayingDevice().contains(device))) {
+ return true;
+ } else {
+ return false;
+ }
}
synchronized boolean isA2dpPlaying(BluetoothDevice device) {
@@ -249,6 +309,11 @@ public class A2dpService extends ProfileService {
public boolean connect(BluetoothDevice device) {
A2dpService service = getService();
if (service == null) return false;
+ //do not allow new connections with active multicast
+ if (service.isMulticastOngoing(device)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore Connection Request");
+ return false;
+ }
return service.connect(device);
}
diff --git a/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java b/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java
index 6cc05dbb4..32c952b15 100644
--- a/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java
+++ b/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -106,6 +109,8 @@ final class A2dpSinkStateMachine extends StateMachine {
private AudioDevicePort mInPortA2dpSink;
private AudioDevicePort mOutPortSpeaker;
private AudioPatch mA2dpSinkAudioPatch;
+ private static final int maxA2dpSinkConnections = 1;
+ private static final int multiCastState = 0;
// mCurrentDevice is the device connected before the state changes
// mTargetDevice is the device to be connected
@@ -147,7 +152,8 @@ final class A2dpSinkStateMachine extends StateMachine {
mContext = context;
mAdapter = BluetoothAdapter.getDefaultAdapter();
- initNative();
+ // for sink soft handsoff and multicast are disabled
+ initNative(maxA2dpSinkConnections, multiCastState);
mDisconnected = new Disconnected();
mPending = new Pending();
@@ -1129,7 +1135,8 @@ final class A2dpSinkStateMachine extends StateMachine {
final static int AUDIO_STATE_STARTED = 2;
private native static void classInitNative();
- private native void initNative();
+ private native void initNative(int maxA2dpConnectionsAllowed,
+ int multiCastState);
private native void cleanupNative();
private native boolean connectA2dpNative(byte[] address);
private native boolean disconnectA2dpNative(byte[] address);
diff --git a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index 745198cce..46dc253c7 100644
--- a/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,6 +28,11 @@
* CONNECTED | | CONNECT
* V |
* (Connected)
+ * | ^
+ * CONNECTING/DISCONNECTING | | CONNECTED/DISCONNECTED
+ * V |
+ * (MultiConnectionpending)
+
*/
package com.android.bluetooth.a2dp;
@@ -59,18 +67,34 @@ import java.util.Set;
final class A2dpStateMachine extends StateMachine {
private static final boolean DBG = true;
+ private static final String TAG="A2dpStateMachine";
static final int CONNECT = 1;
static final int DISCONNECT = 2;
private static final int STACK_EVENT = 101;
private static final int CONNECT_TIMEOUT = 201;
+ /* Allow time for possible LMP response timeout + Page timeout */
+ private static final int CONNECT_TIMEOUT_SEC = 38000;
+
+
+ // Max number of A2dp connections at any time
+ private int maxA2dpConnections = 1;
private static final int IS_INVALID_DEVICE = 0;
private static final int IS_VALID_DEVICE = 1;
+ // enable disable multicast
+ private static final int DISABLE_MULTICAST = 0;
+ private static final int ENABLE_MULTICAST = 1;
+ private static boolean isMultiCastEnabled = false;
+ private static boolean isScanDisabled = false;
+ private static boolean isMultiCastFeatureEnabled = false;
+
private Disconnected mDisconnected;
private Pending mPending;
private Connected mConnected;
+ // Multi A2dp: add new class object
+ private MultiConnectionPending mMultiConnectionPending;
private A2dpService mService;
private Context mContext;
@@ -88,6 +112,9 @@ final class A2dpStateMachine extends StateMachine {
// and mTargetDevice are null
// when either mCurrentDevice or mTargetDevice is not null,
// mIncomingDevice is null
+ // mMultiDisconnectDevice is the device for which disconnect is initiated
+ // in connected state.It is cleared when disconnected event is recieved
+ // from stack.
// Stable states
// No connection, Disconnected state
// both mCurrentDevice and mTargetDevice are null
@@ -103,31 +130,51 @@ final class A2dpStateMachine extends StateMachine {
// mCurrentDevice is not null, mTargetDevice is null
// Incoming connections Pending
// Both mCurrentDevice and mTargetDevice are null
+ // MultiConnectionPending to hanle connection/disconnection for new device
+ // when already connected to one device
+
private BluetoothDevice mCurrentDevice = null;
private BluetoothDevice mTargetDevice = null;
private BluetoothDevice mIncomingDevice = null;
- private BluetoothDevice mPlayingA2dpDevice = null;
-
+ private BluetoothDevice mMultiDisconnectDevice = null;
+ // Multi A2dp: Connected devices list holds all currently connected headsets
+ private ArrayList<BluetoothDevice> mConnectedDevicesList =
+ new ArrayList<BluetoothDevice>();
+ private ArrayList<BluetoothDevice> mPlayingA2dpDevice =
+ new ArrayList<BluetoothDevice>();
static {
classInitNative();
}
- private A2dpStateMachine(A2dpService svc, Context context) {
+ private A2dpStateMachine(A2dpService svc, Context context, int
+ maxConnections, int multiCastState) {
super("A2dpStateMachine");
mService = svc;
mContext = context;
mAdapter = BluetoothAdapter.getDefaultAdapter();
+ maxA2dpConnections = maxConnections;
+ // By default isMultiCastEnabled is set to false, value changes based on stack update
+ isMultiCastEnabled = false;
+ if (multiCastState == 1) {
+ isMultiCastFeatureEnabled = true;
+ } else {
+ isMultiCastFeatureEnabled = false;
+ }
- initNative();
+ initNative(maxA2dpConnections, multiCastState);
mDisconnected = new Disconnected();
mPending = new Pending();
mConnected = new Connected();
+ // Multi A2dp: initialise new class variable
+ mMultiConnectionPending = new MultiConnectionPending();
addState(mDisconnected);
addState(mPending);
addState(mConnected);
+ // Multi A2dp: add State
+ addState(mMultiConnectionPending);
setInitialState(mDisconnected);
@@ -139,9 +186,11 @@ final class A2dpStateMachine extends StateMachine {
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
- static A2dpStateMachine make(A2dpService svc, Context context) {
+ static A2dpStateMachine make(A2dpService svc, Context context,
+ int maxConnections, int multiCastState) {
Log.d("A2dpStateMachine", "make");
- A2dpStateMachine a2dpSm = new A2dpStateMachine(svc, context);
+ A2dpStateMachine a2dpSm = new A2dpStateMachine(svc, context,
+ maxConnections, multiCastState);
a2dpSm.start();
return a2dpSm;
}
@@ -153,6 +202,14 @@ final class A2dpStateMachine extends StateMachine {
broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.STATE_CONNECTING);
}
+
+ if ((mIncomingDevice!= null) &&
+ (getConnectionState(mIncomingDevice) == BluetoothProfile.STATE_CONNECTING)) {
+ log("doQuit()- Move A2DP State to DISCONNECTED");
+ broadcastConnectionState(mIncomingDevice, BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ }
+
quitNow();
}
@@ -164,13 +221,24 @@ final class A2dpStateMachine extends StateMachine {
@Override
public void enter() {
log("Enter Disconnected: " + getCurrentMessage().what);
+ log("mConnectedDevicesList size: " + mConnectedDevicesList.size());
+ // Remove Timeout msg when moved to stable state
+ removeMessages(CONNECT_TIMEOUT);
+ mCurrentDevice = null;
}
@Override
public boolean processMessage(Message message) {
log("Disconnected process message: " + message.what);
- if (mCurrentDevice != null || mTargetDevice != null || mIncomingDevice != null) {
- loge("ERROR: current, target, or mIncomingDevice not null in Disconnected");
+ log("mConnectedDevicesList size: " + mConnectedDevicesList.size());
+ if (mCurrentDevice != null || mTargetDevice != null || mIncomingDevice != null
+ || mConnectedDevicesList.size() != 0) {
+ loge("ERROR: mConnectedDevicesList is not empty," +
+ "current, target, or mIncomingDevice not null in Disconnected");
+ loge("mCurrentDevice is " + mCurrentDevice);
+ loge("mTargetDevice is " + mTargetDevice);
+ loge("mIncomingDevice is " + mIncomingDevice);
+ loge("mConnectedDevicesList.size() is " + mConnectedDevicesList.size());
return NOT_HANDLED;
}
@@ -193,7 +261,9 @@ final class A2dpStateMachine extends StateMachine {
}
// TODO(BT) remove CONNECT_TIMEOUT when the stack
// sends back events consistently
- sendMessageDelayed(CONNECT_TIMEOUT, 30000);
+ Message m = obtainMessage(CONNECT_TIMEOUT);
+ m.obj = device;
+ sendMessageDelayed(m, CONNECT_TIMEOUT_SEC);
break;
case DISCONNECT:
// ignore
@@ -222,12 +292,14 @@ final class A2dpStateMachine extends StateMachine {
// in Disconnected state
private void processConnectionEvent(int state, BluetoothDevice device) {
+ log("processConnectionEvent state = " + state +
+ ", device = " + device);
switch (state) {
case CONNECTION_STATE_DISCONNECTED:
- logw("Ignore HF DISCONNECTED event, device: " + device);
+ logw("Ignore A2DP DISCONNECTED event, device: " + device);
break;
case CONNECTION_STATE_CONNECTING:
- if (okToConnect(device)){
+ if (okToConnect(device)) {
logi("Incoming A2DP accepted");
broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_DISCONNECTED);
@@ -243,20 +315,25 @@ final class A2dpStateMachine extends StateMachine {
AdapterService adapterService = AdapterService.getAdapterService();
if (adapterService != null) {
adapterService.connectOtherProfile(device,
- AdapterService.PROFILE_CONN_REJECTED);
+ AdapterService.PROFILE_CONN_REJECTED);
}
}
break;
case CONNECTION_STATE_CONNECTED:
logw("A2DP Connected from Disconnected state");
- if (okToConnect(device)){
+ if (okToConnect(device)) {
logi("Incoming A2DP accepted");
- broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_DISCONNECTED);
synchronized (A2dpStateMachine.this) {
+ if (!mConnectedDevicesList.contains(device)) {
+ mConnectedDevicesList.add(device);
+ log( "device " + device.getAddress() +
+ " is adding in Disconnected state");
+ }
mCurrentDevice = device;
transitionTo(mConnected);
}
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTED);
} else {
//reject the connection and stay in Disconnected state itself
logi("Incoming A2DP rejected");
@@ -287,7 +364,8 @@ final class A2dpStateMachine extends StateMachine {
@Override
public boolean processMessage(Message message) {
- log("Pending process message: " + message.what);
+ log("Pending process message: " + message.what + ", size: "
+ + mConnectedDevicesList.size());
boolean retValue = HANDLED;
switch(message.what) {
@@ -295,15 +373,27 @@ final class A2dpStateMachine extends StateMachine {
deferMessage(message);
break;
case CONNECT_TIMEOUT:
+ // This is always for Outgoing connection
+ BluetoothDevice device = (BluetoothDevice) message.obj;
+ // getByteAddress has no null check
+ Log.v(TAG,"device for timeout is " + device);
+ if (device != null && (mTargetDevice == null ||
+ !mTargetDevice.equals(device))) {
+ log("Timeout for unknown device " + device);
+ onConnectionStateChanged(CONNECTION_STATE_DISCONNECTED,
+ getByteAddress(device));
+ break;
+ }
+ disconnectA2dpNative(getByteAddress(mTargetDevice));
onConnectionStateChanged(CONNECTION_STATE_DISCONNECTED,
getByteAddress(mTargetDevice));
break;
case DISCONNECT:
- BluetoothDevice device = (BluetoothDevice) message.obj;
+ BluetoothDevice dev = (BluetoothDevice) message.obj;
if (mCurrentDevice != null && mTargetDevice != null &&
- mTargetDevice.equals(device) ) {
+ mTargetDevice.equals(dev) ) {
// cancel connection to the mTargetDevice
- broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
+ broadcastConnectionState(dev, BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.STATE_CONNECTING);
synchronized (A2dpStateMachine.this) {
mTargetDevice = null;
@@ -332,21 +422,51 @@ final class A2dpStateMachine extends StateMachine {
// in Pending state
private void processConnectionEvent(int state, BluetoothDevice device) {
+ log("processConnectionEvent state = " + state +
+ ", device = " + device);
switch (state) {
case CONNECTION_STATE_DISCONNECTED:
- if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) {
- broadcastConnectionState(mCurrentDevice,
- BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_DISCONNECTING);
+ // remove this device from playing device list
+ if (mPlayingA2dpDevice.size() != 0 &&
+ mPlayingA2dpDevice.contains(device)) {
+ log ("Playing A2dp Device is disconnected, setting it to null");
+ broadcastAudioState(device,
+ BluetoothA2dp.STATE_NOT_PLAYING,
+ BluetoothA2dp.STATE_PLAYING);
+ mPlayingA2dpDevice.remove(device);
+ }
+ // Reset scan mode if it set due to multicast
+ Log.i(TAG,"getScanMode " + mAdapter.getScanMode() +
+ " isScanDisabled: " + isScanDisabled);
+ if (mPlayingA2dpDevice.size() <= 1 &&
+ (mAdapter.getScanMode() ==
+ BluetoothAdapter.SCAN_MODE_NONE) &&
+ isScanDisabled) {
+ isScanDisabled = false;
+ AdapterService adapterService =
+ AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.restoreScanMode();
+ }
+ }
+ if (mConnectedDevicesList.contains(device)) {
+ synchronized (A2dpStateMachine.this) {
+ mConnectedDevicesList.remove(device);
+ log( "device " + device.getAddress() +
+ " is removed in Pending state");
+ }
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_DISCONNECTING);
synchronized (A2dpStateMachine.this) {
mCurrentDevice = null;
}
-
+ log("disconnected for target in pending state " + mTargetDevice);
if (mTargetDevice != null) {
if (!connectA2dpNative(getByteAddress(mTargetDevice))) {
broadcastConnectionState(mTargetDevice,
- BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
synchronized (A2dpStateMachine.this) {
mTargetDevice = null;
transitionTo(mDisconnected);
@@ -355,13 +475,18 @@ final class A2dpStateMachine extends StateMachine {
} else {
synchronized (A2dpStateMachine.this) {
mIncomingDevice = null;
- transitionTo(mDisconnected);
+ if (mConnectedDevicesList.size() == 0) {
+ transitionTo(mDisconnected);
+ } else {
+ processMultiA2dpDisconnected(device);
+ }
}
}
} else if (mTargetDevice != null && mTargetDevice.equals(device)) {
// outgoing connection failed
- broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ broadcastConnectionState(mTargetDevice,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
// check if there is some incoming connection request
if (mIncomingDevice != null) {
logi("disconnect for outgoing in pending state");
@@ -372,72 +497,121 @@ final class A2dpStateMachine extends StateMachine {
}
synchronized (A2dpStateMachine.this) {
mTargetDevice = null;
- transitionTo(mDisconnected);
+ if (mConnectedDevicesList.size() == 0) {
+ transitionTo(mDisconnected);
+ } else {
+ transitionTo(mConnected);
+ }
}
} else if (mIncomingDevice != null && mIncomingDevice.equals(device)) {
broadcastConnectionState(mIncomingDevice,
- BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ // check if there is some outgoing connection request
+ if (mTargetDevice != null) {
+ logi("disconnect for incoming in pending state");
+ synchronized (A2dpStateMachine.this) {
+ mIncomingDevice = null;
+ }
+ break;
+ }
synchronized (A2dpStateMachine.this) {
mIncomingDevice = null;
- transitionTo(mDisconnected);
+ if (mConnectedDevicesList.size() == 0) {
+ transitionTo(mDisconnected);
+ } else {
+ transitionTo(mConnected);
+ }
}
} else {
loge("Unknown device Disconnected: " + device);
}
break;
case CONNECTION_STATE_CONNECTED:
- if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) {
+ if (mConnectedDevicesList.contains(device)) {
// disconnection failed
- broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_DISCONNECTING);
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTING);
if (mTargetDevice != null) {
broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ BluetoothProfile.STATE_CONNECTING);
}
synchronized (A2dpStateMachine.this) {
mTargetDevice = null;
transitionTo(mConnected);
}
} else if (mTargetDevice != null && mTargetDevice.equals(device)) {
- broadcastConnectionState(mTargetDevice, BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_CONNECTING);
synchronized (A2dpStateMachine.this) {
mCurrentDevice = mTargetDevice;
+ mConnectedDevicesList.add(mTargetDevice);
mTargetDevice = null;
- transitionTo(mConnected);
+ log( "device " + device.getAddress() +
+ " is added in Pending state");
+ if (mIncomingDevice == null ||
+ (mIncomingDevice != null && !okToConnect(mIncomingDevice)))
+ transitionTo(mConnected);
}
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
} else if (mIncomingDevice != null && mIncomingDevice.equals(device)) {
- broadcastConnectionState(mIncomingDevice, BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_CONNECTING);
// check for a2dp connection allowed for this device in race condition
if (okToConnect(mIncomingDevice)) {
logi("Ready to connect incoming Connection from pending state");
synchronized (A2dpStateMachine.this) {
mCurrentDevice = mIncomingDevice;
+ mConnectedDevicesList.add(mIncomingDevice);
mIncomingDevice = null;
- transitionTo(mConnected);
+ if (mTargetDevice == null)
+ transitionTo(mConnected);
+ log( "device " + device.getAddress() +
+ " is added in Pending state");
}
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
} else {
// A2dp connection unchecked for this device
loge("Incoming A2DP rejected from pending state");
disconnectA2dpNative(getByteAddress(device));
+ // the other profile connection should be initiated
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.connectOtherProfile(device,
+ AdapterService.PROFILE_CONN_REJECTED);
+ }
}
} else {
loge("Unknown device Connected: " + device);
// something is wrong here, but sync our state with stack
- broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_DISCONNECTED);
- synchronized (A2dpStateMachine.this) {
- mCurrentDevice = device;
- mTargetDevice = null;
- mIncomingDevice = null;
- transitionTo(mConnected);
+ if (okToConnect(device)) {
+ synchronized (A2dpStateMachine.this) {
+ mConnectedDevicesList.add(device);
+ if (mTargetDevice != null) {
+ log("Waiting for Connected event for mTargetDevice");
+ } else if (mIncomingDevice != null) {
+ log("Waiting for Connected event for mIncomingDevice");
+ }
+ log( "device " + device.getAddress() +
+ " is added in Pending state");
+ }
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTED);
+ } else {
+ //reject the connection and stay in Pending state itself
+ Log.i(TAG,"Incoming A2dp rejected. priority=" +
+ mService.getPriority(device) + " bondState=" +
+ device.getBondState());
+ disconnectA2dpNative(getByteAddress(device));
+ // the other profile connection should be initiated
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.connectOtherProfile(device,
+ AdapterService.PROFILE_CONN_REJECTED);
+ }
}
}
break;
case CONNECTION_STATE_CONNECTING:
- if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) {
+ if (mConnectedDevicesList.contains(device)) {
log("current device tries to connect back");
// TODO(BT) ignore or reject
} else if (mTargetDevice != null && mTargetDevice.equals(device)) {
@@ -446,15 +620,31 @@ final class A2dpStateMachine extends StateMachine {
// we already broadcasted the intent, doing nothing here
log("Stack and target device are connecting");
}
- else if (mIncomingDevice != null && mIncomingDevice.equals(device)) {
- loge("Another connecting event on the incoming device");
+ else if (mIncomingDevice != null) {
+ if (mIncomingDevice.equals(device)) {
+ loge("Connecting for same device");
+ } else {
+ log("Processing incoming " + mIncomingDevice +
+ " Rejecting incoming " + device);
+ disconnectA2dpNative(getByteAddress(device));
+ }
} else {
// We get an incoming connecting request while Pending
// TODO(BT) is stack handing this case? let's ignore it for now
log("Incoming connection while pending, accept it");
- broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTED);
- mIncomingDevice = device;
+ if (okToConnect(device)) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+ mIncomingDevice = device;
+ } else {
+ disconnectA2dpNative(getByteAddress(device));
+ // the other profile connection should be initiated
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.connectOtherProfile(device,
+ AdapterService.PROFILE_CONN_REJECTED);
+ }
+ }
}
break;
case CONNECTION_STATE_DISCONNECTING:
@@ -477,6 +667,22 @@ final class A2dpStateMachine extends StateMachine {
}
}
+ private void processMultiA2dpDisconnected(BluetoothDevice device) {
+ log("Pending state: processMultiA2dpDisconnected");
+ /* Assign the current activedevice again if the disconnected
+ device equals to the current active device*/
+ if (mCurrentDevice != null && mCurrentDevice.equals(device)) {
+ int deviceSize = mConnectedDevicesList.size();
+ mCurrentDevice = mConnectedDevicesList.get(deviceSize-1);
+ }
+ transitionTo(mConnected);
+ log("processMultiA2dpDisconnected , the latest mCurrentDevice is:"
+ + mCurrentDevice);
+ log("Pending state: processMultiA2dpDisconnected ," +
+ "fake broadcasting for new mCurrentDevice");
+ broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTED);
+ }
}
private class Connected extends State {
@@ -486,9 +692,12 @@ final class A2dpStateMachine extends StateMachine {
// state. This is to prevent auto connect attempts from disconnecting
// devices that previously successfully connected.
// TODO: This needs to check for multiple A2DP connections, once supported...
- removeDeferredMessages(CONNECT);
-
- log("Enter Connected: " + getCurrentMessage().what);
+ log("Enter Connected: " + getCurrentMessage().what +
+ ", size: " + mConnectedDevicesList.size());
+ // remove timeout for connected device only.
+ if (getDeviceForMessage(CONNECT_TIMEOUT) == null) {
+ removeMessages(CONNECT_TIMEOUT);
+ }
// Upon connected, the audio starts out as stopped
broadcastAudioState(mCurrentDevice, BluetoothA2dp.STATE_NOT_PLAYING,
BluetoothA2dp.STATE_PLAYING);
@@ -496,7 +705,8 @@ final class A2dpStateMachine extends StateMachine {
@Override
public boolean processMessage(Message message) {
- log("Connected process message: " + message.what);
+ log("Connected process message: " + message.what +
+ ", size: " + mConnectedDevicesList.size());
if (mCurrentDevice == null) {
loge("ERROR: mCurrentDevice is null in Connected");
return NOT_HANDLED;
@@ -507,41 +717,83 @@ final class A2dpStateMachine extends StateMachine {
case CONNECT:
{
BluetoothDevice device = (BluetoothDevice) message.obj;
- if (mCurrentDevice.equals(device)) {
+ if (device == null) {
+ Log.e(TAG,"device is NULL");
break;
}
-
- broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
- BluetoothProfile.STATE_DISCONNECTED);
- if (!disconnectA2dpNative(getByteAddress(mCurrentDevice))) {
- broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTING);
+ if (mConnectedDevicesList.contains(device)) {
+ Log.e(TAG, "ERROR: Connect received for already connected device, Ignore");
break;
- } else {
- broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_DISCONNECTING,
- BluetoothProfile.STATE_CONNECTED);
}
-
- synchronized (A2dpStateMachine.this) {
- mTargetDevice = device;
- transitionTo(mPending);
+ if (mConnectedDevicesList.size() >= maxA2dpConnections) {
+ BluetoothDevice disconnectConnectedDevice = null;
+ log( "Reach to max size, disconnect one of them first");
+ disconnectConnectedDevice = mConnectedDevicesList.get(0);
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+ if (!disconnectA2dpNative(getByteAddress(disconnectConnectedDevice))) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ break;
+ } else {
+ broadcastConnectionState(disconnectConnectedDevice,
+ BluetoothProfile.STATE_DISCONNECTING,
+ BluetoothProfile.STATE_CONNECTED);
+ }
+ synchronized (A2dpStateMachine.this) {
+ mTargetDevice = device;
+ if (maxA2dpConnections == 1) {
+ transitionTo(mPending);
+ } else {
+ mMultiDisconnectDevice = disconnectConnectedDevice;
+ transitionTo(mMultiConnectionPending);
+ }
+ disconnectConnectedDevice = null;
+ }
+ } else if (mConnectedDevicesList.size() < maxA2dpConnections) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+ if (!connectA2dpNative(getByteAddress(device))) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ break;
+ }
+ synchronized (A2dpStateMachine.this) {
+ mTargetDevice = device;
+ // Transtion to MultiConnectionPending state for
+ // Multi A2dp connection
+ transitionTo(mMultiConnectionPending);
+ }
}
+ Message m = obtainMessage(CONNECT_TIMEOUT);
+ m.obj = device;
+ sendMessageDelayed(m, CONNECT_TIMEOUT_SEC);
+
}
break;
case DISCONNECT:
{
BluetoothDevice device = (BluetoothDevice) message.obj;
- if (!mCurrentDevice.equals(device)) {
+ if (!mConnectedDevicesList.contains(device)) {
+ log("device not connected " + device);
break;
}
+ /* do not remove playing device here, wait for
+ * disconnected event from stack to remove from palying
+ * device.*/
broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING,
- BluetoothProfile.STATE_CONNECTED);
+ BluetoothProfile.STATE_CONNECTED);
if (!disconnectA2dpNative(getByteAddress(device))) {
broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
- BluetoothProfile.STATE_DISCONNECTING);
+ BluetoothProfile.STATE_DISCONNECTING);
break;
}
- transitionTo(mPending);
+ if (mConnectedDevicesList.size() > 1) {
+ mMultiDisconnectDevice = device;
+ transitionTo(mMultiConnectionPending);
+ } else {
+ transitionTo(mPending);
+ }
}
break;
case STACK_EVENT:
@@ -558,6 +810,28 @@ final class A2dpStateMachine extends StateMachine {
break;
}
break;
+ case CONNECT_TIMEOUT:
+ BluetoothDevice timedOutDevice = getDeviceForMessage(CONNECT_TIMEOUT);
+ if ((mTargetDevice == null) || (timedOutDevice == null)) {
+ loge("CONNECT_TIMEOUT received : targetDevice : " +
+ mTargetDevice + " : timedout device : " + timedOutDevice);
+ } else if(mTargetDevice.equals(timedOutDevice)) {
+ loge("CONNECT_TIMEOUT received : connected devices : " +
+ mConnectedDevicesList.size() +
+ " : timedout device : " + timedOutDevice);
+ broadcastConnectionState(mTargetDevice,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ mTargetDevice = null;
+ } else {
+ /* Should not hit this
+ */
+ loge("CONNECT_TIMEOUT received : connected devices : " +
+ mConnectedDevicesList.size() +
+ " : targetDevice : " + mTargetDevice +
+ " : timedout device : " + timedOutDevice);
+ }
+ break;
default:
return NOT_HANDLED;
}
@@ -566,14 +840,51 @@ final class A2dpStateMachine extends StateMachine {
// in Connected state
private void processConnectionEvent(int state, BluetoothDevice device) {
+ log( "processConnectionEvent state = " + state + ", device = "
+ + device);
switch (state) {
case CONNECTION_STATE_DISCONNECTED:
- if (mCurrentDevice.equals(device)) {
- broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.STATE_CONNECTED);
+ if (mConnectedDevicesList.contains(device)) {
+ // if device is playing then remove it from playing
+ // device list.
+ if (mPlayingA2dpDevice.size() != 0 &&
+ mPlayingA2dpDevice.contains(device)) {
+ log ("Playing A2dp Device is disconnected, setting it to null");
+ broadcastAudioState(device,
+ BluetoothA2dp.STATE_NOT_PLAYING,
+ BluetoothA2dp.STATE_PLAYING);
+ mPlayingA2dpDevice.remove(device);
+ }
+ // Reset scan mode if it set due to multicast
+ Log.i(TAG,"getScanMode: " + mAdapter.getScanMode() +
+ " isScanDisabled: " + isScanDisabled);
+ if (mPlayingA2dpDevice.size() <= 1 &&
+ (mAdapter.getScanMode() ==
+ BluetoothAdapter.SCAN_MODE_NONE) &&
+ isScanDisabled) {
+ isScanDisabled = false;
+ AdapterService adapterService =
+ AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.restoreScanMode();
+ }
+ }
+ broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTED);
synchronized (A2dpStateMachine.this) {
- mCurrentDevice = null;
- transitionTo(mDisconnected);
+ mConnectedDevicesList.remove(device);
+ log( "device " + device.getAddress() +
+ " is removed in Connected state");
+ if (mConnectedDevicesList.size() == 0) {
+ mCurrentDevice = null;
+ // cleanup mMultiDisconnectDevice, if incoming
+ // disconnect is processed first.
+ if (mMultiDisconnectDevice != null)
+ mMultiDisconnectDevice = null;
+ transitionTo(mDisconnected);
+ } else {
+ processMultiA2dpDisconnected(device);
+ }
}
} else if (mTargetDevice != null && mTargetDevice.equals(device)) {
broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
@@ -581,38 +892,583 @@ final class A2dpStateMachine extends StateMachine {
synchronized (A2dpStateMachine.this) {
mTargetDevice = null;
}
- logi("Disconnected from mTargetDevice in connected state device: " + device);
+ logi("Disconnected from mTargetDevice in connected state device: " +
+ device);
} else {
loge("Disconnected from unknown device: " + device);
}
break;
+ case CONNECTION_STATE_CONNECTING:
+ // 2nd incoming connection
+ log("Incoming connection in Connected State for device " +
+ device);
+ if (mConnectedDevicesList.contains(device)) {
+ log("device is already connected ");
+ mIncomingDevice = null;
+ mTargetDevice = null;
+ break;
+ }
+ // this should be never be case, as we will move to MPC
+ if (mTargetDevice != null) {
+ log("Outgoing initiated before incoming");
+ disconnectA2dpNative(getByteAddress(device));
+ // the other profile connection should be initiated
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.connectOtherProfile(device,
+ AdapterService.PROFILE_CONN_REJECTED);
+ }
+ break;
+ }
+ if (okToConnect(device) &&
+ (mConnectedDevicesList.size() < maxA2dpConnections)) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+ mIncomingDevice = device;
+ transitionTo(mMultiConnectionPending);
+ Message m = obtainMessage(CONNECT_TIMEOUT);
+ m.obj = device;
+ sendMessageDelayed(m, CONNECT_TIMEOUT_SEC);
+ } else {
+ disconnectA2dpNative(getByteAddress(device));
+ // the other profile connection should be initiated
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.connectOtherProfile(device,
+ AdapterService.PROFILE_CONN_REJECTED);
+ }
+ }
+
+ break;
+ case CONNECTION_STATE_CONNECTED:
+ // 2nd incoming connection
+ log("Connected event for device " + device);
+ if (mConnectedDevicesList.contains(device)) {
+ log("device already connected ");
+ mIncomingDevice = null;
+ mTargetDevice = null;
+ break;
+ }
+ if (mMultiDisconnectDevice != null) {
+ log("disconnection failed for device");
+ mMultiDisconnectDevice = null;
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTING);
+ break;
+ }
+ if (mTargetDevice != null && mTargetDevice.equals(device) &&
+ (mConnectedDevicesList.size() < maxA2dpConnections)) {
+ synchronized (A2dpStateMachine.this) {
+ mCurrentDevice = mTargetDevice;
+ mConnectedDevicesList.add(mTargetDevice);
+ mTargetDevice = null;
+ log( "device " + device.getAddress() +
+ " is added in Connected state");
+ }
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ break;
+ }
+ Log.i(TAG,"okToConnect in connected state " + okToConnect(device));
+ if (okToConnect(device) &&
+ (mConnectedDevicesList.size() < maxA2dpConnections)) {
+ synchronized (A2dpStateMachine.this) {
+ mCurrentDevice = device;
+ mConnectedDevicesList.add(device);
+ mIncomingDevice= null;
+ log( "device " + device.getAddress() +
+ " is added in Connected state");
+ }
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTED);
+ } else {
+ disconnectA2dpNative(getByteAddress(device));
+ // the other profile connection should be initiated
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.connectOtherProfile(device,
+ AdapterService.PROFILE_CONN_REJECTED);
+ }
+ }
+ break;
+ // this case would never happen
+ case CONNECTION_STATE_DISCONNECTING:
+ loge("Disconnecting in Connected State ignore it");
+ break;
+
default:
loge("Connection State Device: " + device + " bad state: " + state);
break;
}
}
+ private void processMultiA2dpDisconnected(BluetoothDevice device) {
+ log("Connect state: processMultiA2dpDisconnected");
+ /* Assign the current activedevice again if the disconnected
+ device equals to the current active device */
+ if (mCurrentDevice != null && mCurrentDevice.equals(device)) {
+ int deviceSize = mConnectedDevicesList.size();
+ mCurrentDevice = mConnectedDevicesList.get(deviceSize-1);
+ }
+ log("processMultiA2dpDisconnected, the latest mCurrentDevice is:" +
+ mCurrentDevice);
+ log("Connect state: processMultiA2dpDisconnected ," +
+ "fake broadcasting for mCurrentDevice");
+ broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTED);
+ }
+
private void processAudioStateEvent(int state, BluetoothDevice device) {
- if (!mCurrentDevice.equals(device)) {
- loge("Audio State Device:" + device + "is different from ConnectedDevice:" +
- mCurrentDevice);
+ if (!mConnectedDevicesList.contains(device)) {
+ loge("Audio State Device:" + device + "is not in mConnectedDevicesList" +
+ mCurrentDevice);
return;
}
+ log("connectedState: processAudioStateEvent state: " + state + " device "
+ + device);
+ log("mPlayingA2dpDevice size is " + mPlayingA2dpDevice.size());
+ log("mConnectedDevicesList size is " +
+ mConnectedDevicesList.contains(device));
switch (state) {
case AUDIO_STATE_STARTED:
- if (mPlayingA2dpDevice == null) {
- mPlayingA2dpDevice = device;
- mService.setAvrcpAudioState(BluetoothA2dp.STATE_PLAYING);
- broadcastAudioState(device, BluetoothA2dp.STATE_PLAYING,
- BluetoothA2dp.STATE_NOT_PLAYING);
+ synchronized (A2dpStateMachine.this) {
+ if (mConnectedDevicesList.contains(device) &&
+ !(mPlayingA2dpDevice.size() != 0 &&
+ mPlayingA2dpDevice.contains(device))) {
+ /* set scan mode before adding device to mPlayingA2dpDevice
+ * so that scan mode is set to last set mode after multicast
+ * is stopped. */
+ if (mPlayingA2dpDevice.size() == 1) {
+ Log.i(TAG,"setScanMode:SCAN_MODE_NONE");
+ isScanDisabled = true;
+ mAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_NONE);
+ }
+ mPlayingA2dpDevice.add(device);
+ mService.setAvrcpAudioState(BluetoothA2dp.STATE_PLAYING, device);
+ broadcastAudioState(device, BluetoothA2dp.STATE_PLAYING,
+ BluetoothA2dp.STATE_NOT_PLAYING);
+ }
+ /* cancel any discovery if in progress and scan mode to
+ * none when multicast is active.Set flag to reset
+ * scan mode if changed due to multicast.*/
+ if (mPlayingA2dpDevice.size() == 2) {
+ if (mAdapter.isDiscovering()) {
+ mAdapter.cancelDiscovery();
+ }
+ }
+ }
+ break;
+ case AUDIO_STATE_STOPPED:
+ case AUDIO_STATE_REMOTE_SUSPEND:
+ synchronized (A2dpStateMachine.this) {
+ if (mPlayingA2dpDevice.size() != 0 &&
+ mPlayingA2dpDevice.contains(device)) {
+ mPlayingA2dpDevice.remove(device);
+ mService.setAvrcpAudioState(BluetoothA2dp.STATE_NOT_PLAYING, device);
+ broadcastAudioState(device, BluetoothA2dp.STATE_NOT_PLAYING,
+ BluetoothA2dp.STATE_PLAYING);
+ }
+ // Reset scan mode if it set due to multicast
+ Log.i(TAG,"getScanMode: " + mAdapter.getScanMode() +
+ " isScanDisabled: " + isScanDisabled);
+ if (mPlayingA2dpDevice.size() <= 1 &&
+ (mAdapter.getScanMode() == BluetoothAdapter.SCAN_MODE_NONE) &&
+ isScanDisabled) {
+ isScanDisabled = false;
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.restoreScanMode();
+ }
+ }
+ }
+ break;
+ default:
+ loge("Audio State Device: " + device + " bad state: " + state);
+ break;
+ }
+ }
+ }
+ /* Add MultiConnectionPending state when atleast 1 HS is connected
+ and disconnect/connect is initiated for new HS */
+ private class MultiConnectionPending extends State {
+ @Override
+ public void enter() {
+ log("Enter MultiConnectionPending: " + getCurrentMessage().what +
+ ", size: " + mConnectedDevicesList.size());
+ }
+
+ public boolean processMessage(Message message) {
+ log( "MultiConnectionPending process message: " + message.what +
+ ", size: " + mConnectedDevicesList.size());
+ boolean retValue = HANDLED;
+ switch(message.what) {
+ case CONNECT:
+ deferMessage(message);
+ break;
+ case DISCONNECT:
+ BluetoothDevice device = (BluetoothDevice) message.obj;
+ if (mConnectedDevicesList.contains(device) &&
+ mTargetDevice != null && mTargetDevice.equals(device)) {
+ // cancel connection to the mTargetDevice
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ synchronized (A2dpStateMachine.this) {
+ mTargetDevice = null;
+ }
+ } else {
+ deferMessage(message);
+ }
+ break;
+ case CONNECT_TIMEOUT:
+ // This is always for Outgoing connection
+ BluetoothDevice dev = (BluetoothDevice)message.obj;
+ // getByteAddress has no null check
+ log("Timeout for device in MCP " + dev);
+ if ((dev != null) && (mTargetDevice == null ||
+ !mTargetDevice.equals(dev))) {
+ log("Timeout for incoming device " + dev);
+ onConnectionStateChanged(CONNECTION_STATE_DISCONNECTED,
+ getByteAddress(dev));
+ break;
+ }
+ disconnectA2dpNative(getByteAddress(mTargetDevice));
+ onConnectionStateChanged(CONNECTION_STATE_DISCONNECTED,
+ getByteAddress(mTargetDevice));
+ break;
+ case STACK_EVENT:
+ StackEvent event = (StackEvent) message.obj;
+ switch (event.type) {
+ case EVENT_TYPE_CONNECTION_STATE_CHANGED:
+ processConnectionEvent(event.valueInt, event.device);
+ break;
+ case EVENT_TYPE_AUDIO_STATE_CHANGED:
+ processAudioStateEvent(event.valueInt, event.device);
+ break;
+ default:
+ loge("Unexpected stack event: " + event.type);
+ break;
+ }
+ break;
+ default:
+ return NOT_HANDLED;
+ }
+ return retValue;
+ }
+
+ @Override
+ public void exit() {
+ log("Exit MultiConnectionPending: " + getCurrentMessage().what);
+ }
+
+ // in MultiConnectionPending state
+ private void processConnectionEvent(int state, BluetoothDevice device) {
+ log("processConnectionEvent state = " + state +
+ ", device = " + device);
+ switch (state) {
+ case CONNECTION_STATE_DISCONNECTED:
+ if (mConnectedDevicesList.contains(device)) {
+ if (mPlayingA2dpDevice.size() != 0 &&
+ mPlayingA2dpDevice.contains(device)) {
+ log ("mPlayingA2dpDevice is disconnected, setting it to null");
+ broadcastAudioState(device, BluetoothA2dp.STATE_NOT_PLAYING,
+ BluetoothA2dp.STATE_PLAYING);
+ mPlayingA2dpDevice.remove(device);
+ }
+ // Reset scan mode if it set due to multicast
+ Log.i(TAG,"getScanMode: " + mAdapter.getScanMode() +
+ " isScanDisabled: " + isScanDisabled);
+ if (mPlayingA2dpDevice.size() <= 1 &&
+ (mAdapter.getScanMode() ==
+ BluetoothAdapter.SCAN_MODE_NONE) &&
+ isScanDisabled) {
+ isScanDisabled = false;
+ AdapterService adapterService =
+ AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.restoreScanMode();
+ }
+ }
+ if (mMultiDisconnectDevice != null &&
+ mMultiDisconnectDevice.equals(device)) {
+ mMultiDisconnectDevice = null;
+ synchronized (A2dpStateMachine.this) {
+ mConnectedDevicesList.remove(device);
+ log( "device " + device.getAddress() +
+ " is removed in MultiConnectionPending state");
+ }
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_DISCONNECTING);
+ if (mTargetDevice != null) {
+ if (!connectA2dpNative(getByteAddress(mTargetDevice))) {
+ broadcastConnectionState(mTargetDevice,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ synchronized (A2dpStateMachine.this) {
+ mTargetDevice = null;
+ if (mConnectedDevicesList.size() == 0) {
+ // Should be not in this state since it has at least
+ // one HF connected in MultiHFPending state
+ log( "Should be not in this state, error handling");
+ transitionTo(mDisconnected);
+
+ } else {
+ processMultiA2dpDisconnected(device);
+ }
+ }
+ }
+ } else {
+ synchronized (A2dpStateMachine.this) {
+ mIncomingDevice = null;
+ if (mConnectedDevicesList.size() == 0) {
+ transitionTo(mDisconnected);
+ } else {
+ processMultiA2dpDisconnected(device);
+ }
+ }
+ }
+ } else {
+ /* HS disconnected, when other HS is connected */
+ synchronized (A2dpStateMachine.this) {
+ mConnectedDevicesList.remove(device);
+
+ log( "device " + device.getAddress() +
+ " is removed in MultiConnectionPending state");
+ }
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTED);
+ }
+ } else if (mTargetDevice != null && mTargetDevice.equals(device)) {
+ broadcastConnectionState(mTargetDevice,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ synchronized (A2dpStateMachine.this) {
+ mTargetDevice = null;
+ if (mConnectedDevicesList.size() == 0) {
+ transitionTo(mDisconnected);
+ } else {
+ transitionTo(mConnected);
+ }
+ }
+ } else if (mIncomingDevice!= null && mIncomingDevice.equals(device)) {
+ // incoming connection failure
+ broadcastConnectionState(mIncomingDevice,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ synchronized (A2dpStateMachine.this) {
+ mIncomingDevice = null;
+ if (mConnectedDevicesList.size() == 0) {
+ transitionTo(mDisconnected);
+ } else {
+ transitionTo(mConnected);
+ }
+ }
+ } else {
+ // mTargetDevice & mIncomingDevice is made null when
+ // 3rd device is connected, hence move to connected
+ // state if mConnectedDevicesList size is 2 and other
+ // device are null
+ if (mTargetDevice == null && mIncomingDevice == null &&
+ (mConnectedDevicesList.size() ==
+ maxA2dpConnections)) {
+ transitionTo(mConnected);
+ }
+ Log.e(TAG, "Unknown device Disconnected: " + device);
+ }
+
+ break;
+ case CONNECTION_STATE_CONNECTING:
+ if (mTargetDevice != null && mTargetDevice.equals(device)) {
+ log("Outgoing Connection initiated, Ignore it");
+ } else if (mIncomingDevice!= null &&
+ mIncomingDevice.equals(device)) {
+ log("Incoming connection from same device, Ignore it");
+ } else if (mConnectedDevicesList.contains(device)) {
+ log("current device tries to connect back");
+ } else {
+ log("Connection event from new device " + device);
+ if (okToConnect(device) &&
+ (mConnectedDevicesList.size() < maxA2dpConnections)) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+ mIncomingDevice = device;
+ } else {
+ disconnectA2dpNative(getByteAddress(device));
+ // the other profile connection should be initiated
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.connectOtherProfile(device,
+ AdapterService.PROFILE_CONN_REJECTED);
+ }
+ }
+ }
+ break;
+ case CONNECTION_STATE_CONNECTED:
+ log("Connected event for device " + device);
+ if (mConnectedDevicesList.size() == maxA2dpConnections) {
+
+ // Unkown device connected, check for target and
+ // incoming devices, make them null and broadcast
+ // disconnection for them
+ if (mTargetDevice != null && mTargetDevice.equals(device)) {
+ log("mTargetDevice, connected list is full");
+ broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ synchronized (A2dpStateMachine.this) {
+ mTargetDevice = null;
+ }
+ disconnectA2dpNative(getByteAddress(device));
+ onConnectionStateChanged(CONNECTION_STATE_DISCONNECTED,
+ getByteAddress(device));
+ }
+ if (mIncomingDevice != null && mIncomingDevice.equals(device)) {
+ log("mIncomingDevice connected list is full");
+ broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ synchronized (A2dpStateMachine.this) {
+ mIncomingDevice = null;
+ }
+
+ disconnectA2dpNative(getByteAddress(device));
+ onConnectionStateChanged(CONNECTION_STATE_DISCONNECTED,
+ getByteAddress(device));
+ }
+ }
+ if (mConnectedDevicesList.contains(device)) {
+ log("Disconnection failed event for device " + device);
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTING);
+ if (mTargetDevice != null) {
+ broadcastConnectionState(mTargetDevice,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ }
+ synchronized (A2dpStateMachine.this) {
+ mTargetDevice = null;
+ transitionTo(mConnected);
+ }
+ } else if (mTargetDevice != null && mTargetDevice.equals(device)) {
+ synchronized (A2dpStateMachine.this) {
+ mCurrentDevice = device;
+ mConnectedDevicesList.add(device);
+ log( "device " + device.getAddress() +
+ " is added in MultiConnectionPending state");
+ mTargetDevice = null;
+ transitionTo(mConnected);
+ }
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ } else if (mIncomingDevice!= null && mIncomingDevice.equals(device)) {
+ synchronized (A2dpStateMachine.this) {
+ mCurrentDevice = device;
+ mConnectedDevicesList.add(device);
+ log( "device " + device.getAddress() +
+ " is added in MultiConnectionPending state");
+ mIncomingDevice = null;
+ transitionTo(mConnected);
+ }
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+
+ } else {
+ log("Unknown Device connected");
+ if (okToConnect(device) &&
+ (mConnectedDevicesList.size() < maxA2dpConnections)) {
+ mCurrentDevice = device;
+ mConnectedDevicesList.add(device);
+ log( "device " + device.getAddress() +
+ " is added in MultiConnectionPending state");
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTED);
+
+ } else {
+ disconnectA2dpNative(getByteAddress(device));
+ }
+
+ }
+ break;
+ case CONNECTION_STATE_DISCONNECTING:
+ if (mConnectedDevicesList.contains(device)) {
+ // we already broadcasted the intent, doing nothing here
+ log("stack is disconnecting mCurrentDevice");
+ } else if (mTargetDevice != null && mTargetDevice.equals(device)) {
+ loge("TargetDevice is getting disconnected");
+ } else if (mIncomingDevice != null && mIncomingDevice.equals(device)) {
+ loge("mIncomingDevice is getting disconnected");
+ } else {
+ loge("Disconnecting unknow device: " + device);
+ }
+ break;
+ default:
+ loge("Incorrect state: " + state);
+ break;
+
+ }
+
+ }
+
+ private void processAudioStateEvent(int state, BluetoothDevice device) {
+ if (!mConnectedDevicesList.contains(device)) {
+ loge("Audio State Device:" + device + "is not in mConnectedDevicesList" +
+ mCurrentDevice);
+ return;
+ }
+ log("MultiPendingState: processAudioStateEvent state: " + state + " device "
+ + device.getName());
+ log("mPlayingA2dpDevice size is " + mPlayingA2dpDevice.size());
+ log("mConnectedDevicesList size is " + mConnectedDevicesList.size());
+ switch (state) {
+ case AUDIO_STATE_STARTED:
+ synchronized (A2dpStateMachine.this) {
+ if (mConnectedDevicesList.contains(device) &&
+ !(mPlayingA2dpDevice.size()!= 0 &&
+ mPlayingA2dpDevice.contains(device))) {
+ /* set scan mode before adding device to mPlayingA2dpDevice
+ * so that scan mode is set to last set mode after multicast
+ * is stopped. */
+ if (mPlayingA2dpDevice.size() == 1) {
+ Log.i(TAG,"setScanMode:SCAN_MODE_NONE");
+ isScanDisabled = true;
+ mAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_NONE);
+ }
+ mPlayingA2dpDevice.add(device);
+ mService.setAvrcpAudioState(BluetoothA2dp.STATE_PLAYING, device);
+ broadcastAudioState(device, BluetoothA2dp.STATE_PLAYING,
+ BluetoothA2dp.STATE_NOT_PLAYING);
+ }
+ /* cancel any discovery if in progress and scan mode to
+ * none when multicast is active.Set flag to reset
+ * scan mode if changed due to multicast.*/
+ if (mPlayingA2dpDevice.size() == 2) {
+ if (mAdapter.isDiscovering()) {
+ mAdapter.cancelDiscovery();
+ }
+ }
}
break;
case AUDIO_STATE_REMOTE_SUSPEND:
case AUDIO_STATE_STOPPED:
- if (mPlayingA2dpDevice != null) {
- mPlayingA2dpDevice = null;
- mService.setAvrcpAudioState(BluetoothA2dp.STATE_NOT_PLAYING);
- broadcastAudioState(device, BluetoothA2dp.STATE_NOT_PLAYING,
- BluetoothA2dp.STATE_PLAYING);
+ synchronized (A2dpStateMachine.this) {
+ if (mPlayingA2dpDevice.size() != 0 &&
+ mPlayingA2dpDevice.contains(device)) {
+ mPlayingA2dpDevice.remove(device);
+ mService.setAvrcpAudioState(BluetoothA2dp.STATE_NOT_PLAYING, device);
+ broadcastAudioState(device, BluetoothA2dp.STATE_NOT_PLAYING,
+ BluetoothA2dp.STATE_PLAYING);
+ }
+ // Reset scan mode if it set due to multicast
+ Log.i(TAG,"getScanMode: " + mAdapter.getScanMode() +
+ " isScanDisabled: " + isScanDisabled);
+ if (mPlayingA2dpDevice.size() <= 1 &&
+ (mAdapter.getScanMode() == BluetoothAdapter.SCAN_MODE_NONE) &&
+ isScanDisabled) {
+ isScanDisabled = false;
+ AdapterService adapterService = AdapterService.getAdapterService();
+ if (adapterService != null) {
+ adapterService.restoreScanMode();
+ }
+ }
}
break;
default:
@@ -620,20 +1476,38 @@ final class A2dpStateMachine extends StateMachine {
break;
}
}
+
+ private void processMultiA2dpDisconnected(BluetoothDevice device) {
+ log("processMultiA2dpDisconnected state: processMultiA2dpDisconnected");
+
+ if (mCurrentDevice != null && mCurrentDevice.equals(device)) {
+ int deviceSize = mConnectedDevicesList.size();
+ mCurrentDevice = mConnectedDevicesList.get(deviceSize-1);
+ }
+ transitionTo(mConnected);
+ log("processMultiA2dpDisconnected , the latest mCurrentDevice is:"
+ + mCurrentDevice);
+ log("MultiA2dpPending state: processMultiA2dpDisconnected ," +
+ "fake broadcasting for mCurrentDevice");
+ broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED,
+ BluetoothProfile.STATE_DISCONNECTED);
+ }
}
int getConnectionState(BluetoothDevice device) {
if (getCurrentState() == mDisconnected) {
+ log( "currentState is Disconnected");
return BluetoothProfile.STATE_DISCONNECTED;
}
synchronized (this) {
IState currentState = getCurrentState();
+ log( "currentState = " + currentState);
if (currentState == mPending) {
if ((mTargetDevice != null) && mTargetDevice.equals(device)) {
return BluetoothProfile.STATE_CONNECTING;
}
- if ((mCurrentDevice != null) && mCurrentDevice.equals(device)) {
+ if (mConnectedDevicesList.contains(device)) {
return BluetoothProfile.STATE_DISCONNECTING;
}
if ((mIncomingDevice != null) && mIncomingDevice.equals(device)) {
@@ -642,8 +1516,26 @@ final class A2dpStateMachine extends StateMachine {
return BluetoothProfile.STATE_DISCONNECTED;
}
+ if (currentState == mMultiConnectionPending) {
+ if ((mTargetDevice != null) && mTargetDevice.equals(device)) {
+ return BluetoothProfile.STATE_CONNECTING;
+ }
+ if ((mIncomingDevice != null) && mIncomingDevice.equals(device)) {
+ return BluetoothProfile.STATE_CONNECTING; // incoming connection
+ }
+ if (mConnectedDevicesList.contains(device)) {
+ if ((mMultiDisconnectDevice != null) &&
+ (!mMultiDisconnectDevice.equals(device))) {
+ // The device is still connected
+ return BluetoothProfile.STATE_CONNECTED;
+ }
+ return BluetoothProfile.STATE_DISCONNECTING;
+ }
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
if (currentState == mConnected) {
- if (mCurrentDevice.equals(device)) {
+ if (mConnectedDevicesList.contains(device)) {
return BluetoothProfile.STATE_CONNECTED;
}
return BluetoothProfile.STATE_DISCONNECTED;
@@ -656,9 +1548,12 @@ final class A2dpStateMachine extends StateMachine {
List<BluetoothDevice> getConnectedDevices() {
List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
+ Log.i(TAG,"mConnectedDevicesList size is " +
+ mConnectedDevicesList.size());
synchronized(this) {
- if (getCurrentState() == mConnected) {
- devices.add(mCurrentDevice);
+ /* If connected and mCurrentDevice is not null*/
+ for (int i = 0; i < mConnectedDevicesList.size(); i++) {
+ devices.add(mConnectedDevicesList.get(i));
}
}
return devices;
@@ -666,13 +1561,25 @@ final class A2dpStateMachine extends StateMachine {
boolean isPlaying(BluetoothDevice device) {
synchronized(this) {
- if (device.equals(mPlayingA2dpDevice)) {
+ if (mPlayingA2dpDevice.contains(device)) {
return true;
}
}
return false;
}
+ public List<BluetoothDevice> getPlayingDevice() {
+ return mPlayingA2dpDevice;
+ }
+
+ public boolean isMulticastEnabled() {
+ return isMultiCastEnabled;
+ }
+
+ public boolean isMulticastFeatureEnabled() {
+ return isMultiCastFeatureEnabled;
+ }
+
boolean okToConnect(BluetoothDevice device) {
AdapterService adapterService = AdapterService.getAdapterService();
int priority = mService.getPriority(device);
@@ -714,12 +1621,33 @@ final class A2dpStateMachine extends StateMachine {
return deviceList;
}
+ private BluetoothDevice getDeviceForMessage(int what) {
+ if (what == CONNECT_TIMEOUT) {
+ log("getDeviceForMessage: returning mTargetDevice for what=" + what);
+ return mTargetDevice;
+ }
+ if (mConnectedDevicesList.size() == 0) {
+ log("getDeviceForMessage: No connected device. what=" + what);
+ return null;
+ }
+ for (BluetoothDevice device : mConnectedDevicesList){
+ if (getHandler().hasMessages(what, device)) {
+ log("getDeviceForMessage: returning " + device + "for what " +
+ what);
+ return device;
+ }
+ }
+ log("getDeviceForMessage: No matching device for " + what + ". Returning null");
+ return null;
+ }
+
// This method does not check for error conditon (newState == prevState)
private void broadcastConnectionState(BluetoothDevice device, int newState, int prevState) {
int delay = mAudioManager.setBluetoothA2dpDeviceConnectionState(device, newState,
BluetoothProfile.A2DP);
+ Log.i(TAG,"connectoin state change " + device + " state " + newState);
if (newState == BluetoothProfile.STATE_DISCONNECTING ||
newState == BluetoothProfile.STATE_CONNECTING) {
@@ -769,10 +1697,20 @@ final class A2dpStateMachine extends StateMachine {
logw(" device " + device + " okToConnect " + okToConnect(device));
if (okToConnect(device)) {
// if connection is allowed then go ahead and connect
- allowConnectionNative(IS_VALID_DEVICE);
+ allowConnectionNative(IS_VALID_DEVICE, getByteAddress(device));
} else {
// if connection is not allowed DO NOT CONNECT
- allowConnectionNative(IS_INVALID_DEVICE);
+ allowConnectionNative(IS_INVALID_DEVICE, getByteAddress(device));
+ }
+ }
+
+ private void onMulticastStateChanged(int state) {
+ if (state == ENABLE_MULTICAST) {
+ Log.i(TAG,"A2dp Multicast is Enabled");
+ isMultiCastEnabled = true;
+ } else {
+ Log.i(TAG,"A2dp Multicast is Disabled");
+ isMultiCastEnabled = false;
}
}
@@ -841,9 +1779,10 @@ final class A2dpStateMachine extends StateMachine {
final static int AUDIO_STATE_STARTED = 2;
private native static void classInitNative();
- private native void initNative();
+ private native void initNative(int maxA2dpConnectionsAllowed,
+ int multiCastState);
private native void cleanupNative();
private native boolean connectA2dpNative(byte[] address);
private native boolean disconnectA2dpNative(byte[] address);
- private native void allowConnectionNative(int isValid);
+ private native void allowConnectionNative(int isValid, byte[] address);
}
diff --git a/src/com/android/bluetooth/avrcp/Avrcp.java b/src/com/android/bluetooth/avrcp/Avrcp.java
index 3c9dd2d77..67647c37f 100755..100644
--- a/src/com/android/bluetooth/avrcp/Avrcp.java
+++ b/src/com/android/bluetooth/avrcp/Avrcp.java
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2013-2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +23,10 @@ import java.util.Timer;
import java.util.TimerTask;
import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAvrcp;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -47,6 +52,7 @@ import android.util.Log;
import android.view.KeyEvent;
import android.content.BroadcastReceiver;
+import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.Utils;
@@ -76,36 +82,34 @@ public final class Avrcp {
private Context mContext;
private final AudioManager mAudioManager;
+ private A2dpService mA2dpService;
private AvrcpMessageHandler mHandler;
private RemoteController mRemoteController;
private RemoteControllerWeak mRemoteControllerCb;
private AvrcpRemoteControllerWeak mAvrcpRemoteControllerCb;
private Metadata mMetadata;
private int mTransportControlFlags;
- private int mCurrentPlayState;
+ private int mCurrentPlayerState;
private int mPlayStatusChangedNT;
- private int mPlayerStatusChangeNT;
private int mTrackChangedNT;
- private long mTrackNumber;
private long mCurrentPosMs;
private long mPlayStartTimeMs;
+ private long mTrackNumber;
private long mSongLengthMs;
private long mPlaybackIntervalMs;
private int mPlayPosChangedNT;
- private long mNextPosMs;
- private long mPrevPosMs;
private long mSkipStartTime;
- private int mFeatures;
- private int mAbsoluteVolume;
- private int mLastSetVolume;
- private int mLastDirection;
private final int mVolumeStep;
private final int mAudioStreamMax;
- private boolean mVolCmdInProgress;
- private int mAbsVolRetryTimes;
private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
private int mSkipAmount;
+ private final BluetoothAdapter mAdapter;
+ private static Uri mMediaUriStatic;
+ private static long currentTrackPos;
+ private static boolean updatePlayTime;
+ private static boolean updateValues;
+ private int mAddressedPlayerId;
/* BTRC features */
public static final int BTRC_FEAT_METADATA = 0x01;
@@ -145,12 +149,6 @@ public final class Avrcp {
private static final int MESSAGE_PLAY_ITEM = 2006;
private static final int MESSAGE_GET_ITEM_ATTRS = 2007;
- private int mAddressedPlayerChangedNT;
- private int mAvailablePlayersChangedNT;
- private int mNowPlayingContentChangedNT;
- private int mAddressedPlayerId;
- private String mRequestedAddressedPlayerPackageName;
-
private CachedRequest mCachedRequest = null;
private static final int MSG_UPDATE_STATE = 100;
@@ -166,7 +164,6 @@ public final class Avrcp {
private static final int MSG_NOW_PLAYING_ENTRIES_RECEIVED = 207;
private MediaPlayerInfo mediaPlayerInfo1;
- private MediaPlayerInfo mediaPlayerInfo2;
private static final int BUTTON_TIMEOUT_TIME = 2000;
private static final int BASE_SKIP_AMOUNT = 2000;
@@ -185,10 +182,6 @@ public final class Avrcp {
public static final int KEY_STATE_PRESSED = 0;
public static final int KEY_STATE_RELEASED = 1;
- private String mCurrentPath;
- private String mCurrentPathUid;
- private static Uri mMediaUri;
-
private final static int TYPE_MEDIA_PLAYER_ITEM = 0x01;
private final static int TYPE_FOLDER_ITEM = 0x02;
private final static int TYPE_MEDIA_ELEMENT_ITEM = 0x03;
@@ -241,9 +234,78 @@ public final class Avrcp {
private final static int TITLES_ITEM_INDEX = 3;
//Intents for PlayerApplication Settings
- private static final String PLAYERSETTINGS_REQUEST = "org.codeaurora.music.playersettingsrequest";
+ private static final String PLAYERSETTINGS_REQUEST =
+ "org.codeaurora.music.playersettingsrequest";
private static final String PLAYERSETTINGS_RESPONSE =
- "org.codeaurora.music.playersettingsresponse";
+ "org.codeaurora.music.playersettingsresponse";
+ // Max number of Avrcp connections at any time
+ private int maxAvrcpConnections = 1;
+ BluetoothDevice mBrowserDevice = null;
+ private static final int INVALID_DEVICE_INDEX = 0xFF;
+ // codes for reset of of notifications
+ private static final int PLAY_POSITION_CHANGE_NOTIFICATION = 101;
+ private static final int PLAY_STATUS_CHANGE_NOTIFICATION = 102;
+ private static final int TRACK_CHANGE_NOTIFICATION = 103;
+ private static final int NOW_PALYING_CONTENT_CHANGED_NOTIFICATION = 104;
+
+ private static final int INVALID_ADDRESSED_PLAYER_ID = -1;
+ // Device dependent registered Notification & Variables
+ private class DeviceDependentFeature {
+ private BluetoothDevice mCurrentDevice;
+ private int mCurrentPlayState;
+ private int mPlayStatusChangedNT;
+ private int mPlayerStatusChangeNT;
+ private int mTrackChangedNT;
+ private long mNextPosMs;
+ private long mPrevPosMs;
+ private long mPlaybackIntervalMs;
+ private int mPlayPosChangedNT;
+ private int mFeatures;
+ private int mAbsoluteVolume;
+ private int mLastSetVolume;
+ private int mLastDirection;
+ private boolean mVolCmdInProgress;
+ private int mAbsVolRetryTimes;
+ private int keyPressState;
+ private int mAddressedPlayerChangedNT;
+ private int mAvailablePlayersChangedNT;
+ private int mNowPlayingContentChangedNT;
+ private String mRequestedAddressedPlayerPackageName;
+ private String mCurrentPath;
+ private String mCurrentPathUid;
+ private Uri mMediaUri;
+ private boolean isMusicAppResponsePending;
+ private boolean isBrowsingSupported;
+ private boolean isAbsoluteVolumeSupportingDevice;
+
+ public DeviceDependentFeature() {
+ mCurrentDevice = null;
+ mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE;
+ mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
+ mPlayerStatusChangeNT = NOTIFICATION_TYPE_CHANGED;
+ mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
+ mPlaybackIntervalMs = 0L;
+ mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
+ mFeatures = 0;
+ mAbsoluteVolume = -1;
+ mLastSetVolume = -1;
+ mLastDirection = 0;
+ mVolCmdInProgress = false;
+ mAbsVolRetryTimes = 0;
+ keyPressState = KEY_STATE_RELEASE; //Key release state
+ mAddressedPlayerChangedNT = NOTIFICATION_TYPE_CHANGED;
+ mAvailablePlayersChangedNT = NOTIFICATION_TYPE_CHANGED;
+ mNowPlayingContentChangedNT = NOTIFICATION_TYPE_CHANGED;
+ mRequestedAddressedPlayerPackageName = null;
+ mCurrentPath = PATH_INVALID;
+ mCurrentPathUid = null;
+ mMediaUri = Uri.EMPTY;
+ isMusicAppResponsePending = false;
+ isBrowsingSupported = false;
+ isAbsoluteVolumeSupportingDevice = false;
+
+ }
+ };
private class PlayerSettings {
public byte attr;
@@ -311,41 +373,32 @@ public final class Avrcp {
private final String UPDATE_VALUE_TEXT = "UpdateValuesText";
private ArrayList <Integer> mPendingCmds;
private ArrayList <Integer> mPendingSetAttributes;
+ DeviceDependentFeature[] deviceFeatures;
static {
classInitNative();
}
- private Avrcp(Context context) {
- if (DEBUG) Log.v(TAG, "Avrcp");
+ private Avrcp(Context context, A2dpService svc, int maxConnections ) {
+ if (DEBUG)
+ Log.v(TAG, "Avrcp");
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
mMetadata = new Metadata();
- mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE; // until we get a callback
- mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
- mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
- mPlayerStatusChangeNT = NOTIFICATION_TYPE_CHANGED;
- mAddressedPlayerChangedNT = NOTIFICATION_TYPE_CHANGED;
- mAvailablePlayersChangedNT = NOTIFICATION_TYPE_CHANGED;
- mNowPlayingContentChangedNT = NOTIFICATION_TYPE_CHANGED;
mTrackNumber = -1L;
mCurrentPosMs = 0L;
mPlayStartTimeMs = -1L;
mSongLengthMs = 0L;
- mPlaybackIntervalMs = 0L;
- mAddressedPlayerId = 0; // 0 signifies bad entry
- mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
- mFeatures = 0;
- mAbsoluteVolume = -1;
- mLastSetVolume = -1;
- mLastDirection = 0;
- mVolCmdInProgress = false;
- mAbsVolRetryTimes = 0;
-
+ mA2dpService = svc;
+ maxAvrcpConnections = maxConnections;
+ deviceFeatures = new DeviceDependentFeature[maxAvrcpConnections];
+ mAddressedPlayerId = INVALID_ADDRESSED_PLAYER_ID;
+ mCurrentPlayerState = RemoteControlClient.PLAYSTATE_NONE;
+ for(int i = 0; i < maxAvrcpConnections; i++) {
+ deviceFeatures[i] = new DeviceDependentFeature();
+ }
mContext = context;
- mCurrentPath = PATH_INVALID;
- mCurrentPathUid = null;
- mMediaUri = Uri.EMPTY;
- initNative();
+ initNative(maxConnections);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mAudioStreamMax = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
@@ -353,16 +406,20 @@ public final class Avrcp {
}
private void start() {
- if (DEBUG) Log.v(TAG, "start");
+ if (DEBUG)
+ Log.v(TAG, "start");
HandlerThread thread = new HandlerThread("BluetoothAvrcpHandler");
thread.start();
Looper looper = thread.getLooper();
mHandler = new AvrcpMessageHandler(looper);
mPendingCmds = new ArrayList<Integer>();
mPendingSetAttributes = new ArrayList<Integer>();
- mCurrentPath = PATH_INVALID;
- mCurrentPathUid = null;
- mMediaUri = Uri.EMPTY;
+ // clear path for all devices
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ deviceFeatures[i].mCurrentPath = PATH_INVALID;
+ deviceFeatures[i].mCurrentPathUid = null;
+ deviceFeatures[i].mMediaUri = Uri.EMPTY;
+ }
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(AudioManager.RCC_CHANGED_ACTION);
intentFilter.addAction(PLAYERSETTINGS_RESPONSE);
@@ -389,16 +446,22 @@ public final class Avrcp {
Log.v(TAG, "received RCC_CHANGED_ACTION");
int isRCCFocussed = 0;
int isRCCAvailable = 0;
- String callingPackageName = intent.getStringExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME);
- boolean isFocussed = intent.getBooleanExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE,false);
- boolean isAvailable = intent.getBooleanExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE, false);
+ String callingPackageName =
+ intent.getStringExtra(AudioManager.EXTRA_CALLING_PACKAGE_NAME);
+ boolean isFocussed =
+ intent.getBooleanExtra(AudioManager.EXTRA_FOCUS_CHANGED_VALUE,
+ false);
+ boolean isAvailable =
+ intent.getBooleanExtra(AudioManager.EXTRA_AVAILABLITY_CHANGED_VALUE,
+ false);
if (isFocussed)
isRCCFocussed = 1;
if (isAvailable)
isRCCAvailable = 1;
Log.v(TAG, "focus: " + isFocussed + " , availability: " + isAvailable);
if (mHandler != null) {
- mHandler.obtainMessage(MSG_UPDATE_RCC_CHANGE, isRCCFocussed, isRCCAvailable, callingPackageName).sendToTarget();
+ mHandler.obtainMessage(MSG_UPDATE_RCC_CHANGE, isRCCFocussed,
+ isRCCAvailable, callingPackageName).sendToTarget();
}
} else if (action.equals(PLAYERSETTINGS_RESPONSE)) {
int getResponse = intent.getIntExtra(EXTRA_GET_RESPONSE,
@@ -406,6 +469,8 @@ public final class Avrcp {
byte [] data;
String [] text;
boolean isSetAttrValRsp = false;
+ BluetoothDevice device = null;
+
synchronized (mPendingCmds) {
Integer val = new Integer(getResponse);
if (mPendingCmds.contains(val)) {
@@ -417,58 +482,112 @@ public final class Avrcp {
mPendingCmds.remove(val);
}
}
- if (DEBUG) Log.v(TAG,"getResponse " + getResponse);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].isMusicAppResponsePending ==
+ true) {
+ device = deviceFeatures[i].mCurrentDevice;
+ deviceFeatures[i].isMusicAppResponsePending = false;
+ break;
+ }
+ }
+
+ if (DEBUG)
+ Log.v(TAG,"getResponse" + getResponse);
switch (getResponse) {
case GET_ATTRIBUTE_IDS:
+ if (device == null) {
+ Log.e(TAG,"ERROR!!! device is null");
+ return;
+ }
data = intent.getByteArrayExtra(EXTRA_ATTIBUTE_ID_ARRAY);
byte numAttr = (byte) data.length;
- if (DEBUG) Log.v(TAG,"GET_ATTRIBUTE_IDS");
- getListPlayerappAttrRspNative(numAttr,data);
+ if (DEBUG)
+ Log.v(TAG,"GET_ATTRIBUTE_IDS");
+ getListPlayerappAttrRspNative(numAttr ,
+ data ,getByteAddress(device));
+
break;
case GET_VALUE_IDS:
+ if (device == null) {
+ Log.e(TAG,"ERROR!!! device is null");
+ return;
+ }
data = intent.getByteArrayExtra(EXTRA_VALUE_ID_ARRAY);
numAttr = (byte) data.length;
- if (DEBUG) Log.v(TAG,"GET_VALUE_IDS " + numAttr);
- getPlayerAppValueRspNative(numAttr, data);
+ if (DEBUG)
+ Log.v(TAG,"GET_VALUE_IDS" + numAttr);
+ getPlayerAppValueRspNative(numAttr, data,
+ getByteAddress(device));
break;
case GET_ATTRIBUTE_VALUES:
+ if (device == null) {
+ Log.e(TAG,"ERROR!!! device is null");
+ return;
+ }
data = intent.getByteArrayExtra(EXTRA_ATTRIB_VALUE_PAIRS);
updateLocalPlayerSettings(data);
numAttr = (byte) data.length;
- if (DEBUG) Log.v(TAG,"GET_ATTRIBUTE_VALUES " + numAttr);
- SendCurrentPlayerValueRspNative(numAttr, data);
+ if (DEBUG)
+ Log.v(TAG,"GET_ATTRIBUTE_VALUES" + numAttr);
+ SendCurrentPlayerValueRspNative(numAttr ,
+ data, getByteAddress(device));
break;
case SET_ATTRIBUTE_VALUES:
data = intent.getByteArrayExtra(EXTRA_ATTRIB_VALUE_PAIRS);
updateLocalPlayerSettings(data);
- Log.v(TAG,"SET_ATTRIBUTE_VALUES: ");
- if (isSetAttrValRsp){
+ if (isSetAttrValRsp) {
isSetAttrValRsp = false;
- Log.v(TAG,"Respond to SET_ATTRIBUTE_VALUES request");
- if (checkPlayerAttributeResponse(data)) {
- SendSetPlayerAppRspNative(OPERATION_SUCCESSFUL);
- } else {
- SendSetPlayerAppRspNative(INTERNAL_ERROR);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mCurrentDevice != null) {
+ Log.v(TAG,"Respond to SET_ATTRIBUTE_VALUES request");
+ if (checkPlayerAttributeResponse(data)) {
+ SendSetPlayerAppRspNative(OPERATION_SUCCESSFUL,
+ getByteAddress(deviceFeatures[i].mCurrentDevice));
+ } else {
+ SendSetPlayerAppRspNative(INTERNAL_ERROR,
+ getByteAddress(deviceFeatures[i].mCurrentDevice));
+ }
+ }
+ }
+ mPendingSetAttributes.clear();
+ }
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mPlayerStatusChangeNT ==
+ NOTIFICATION_TYPE_INTERIM) {
+ Log.v(TAG,"device has registered for"+
+ "mPlayerStatusChangeNT");
+ deviceFeatures[i].mPlayerStatusChangeNT =
+ NOTIFICATION_TYPE_CHANGED;
+ sendPlayerAppChangedRsp(deviceFeatures[i].mPlayerStatusChangeNT,
+ deviceFeatures[i].mCurrentDevice);
+ } else {
+ Log.v(TAG,"Drop Set Attr Val update from media player");
}
- } else if (mPlayerStatusChangeNT == NOTIFICATION_TYPE_INTERIM) {
- Log.v(TAG,"Send Player appl attribute changed response");
- mPlayerStatusChangeNT = NOTIFICATION_TYPE_CHANGED;
- sendPlayerAppChangedRsp(mPlayerStatusChangeNT);
- } else {
- Log.v(TAG,"Drop Set Attr Val update from media player");
}
break;
case GET_ATTRIBUTE_TEXT:
text = intent.getStringArrayExtra(EXTRA_ATTRIBUTE_STRING_ARRAY);
+ if (device == null) {
+ Log.e(TAG,"ERROR!!! device is null");
+ return;
+ }
sendSettingsTextRspNative(mPlayerSettings.attrIds.length ,
- mPlayerSettings.attrIds, text.length,text);
- if (DEBUG) Log.v(TAG,"mPlayerSettings.attrIds"
- + mPlayerSettings.attrIds.length);
+ mPlayerSettings.attrIds ,text.length,
+ text, getByteAddress(device));
+ if (DEBUG)
+ Log.v(TAG,"mPlayerSettings.attrIds"
+ + mPlayerSettings.attrIds.length);
break;
case GET_VALUE_TEXT:
text = intent.getStringArrayExtra(EXTRA_VALUE_STRING_ARRAY);
+ if (device == null) {
+ Log.e(TAG,"ERROR!!! device is null");
+ return;
+ }
sendValueTextRspNative(mPlayerSettings.attrIds.length ,
- mPlayerSettings.attrIds, text.length , text);
+ mPlayerSettings.attrIds,
+ text.length, text,
+ getByteAddress(device));
break;
}
}
@@ -477,17 +596,16 @@ public final class Avrcp {
};
/* This method is used for create entries of existing media players on RCD start
- * Later when media players become avaialable corresponding entries
- * are marked accordingly and similarly when media players changes focus
- * the corresponding fields are modified */
+ * Later when media players become avaialable corresponding entries
+ * are marked accordingly and similarly when media players changes focus
+ * the corresponding fields are modified */
private void registerMediaPlayers () {
- if (DEBUG) Log.v(TAG, "registerMediaPlayers");
+ if (DEBUG)
+ Log.v(TAG, "registerMediaPlayers");
int[] featureMasks = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- int[] featureMasks2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
byte[] playerName1 = {0x4d, 0x75, 0x73, 0x69, 0x63}/*Music*/;
- byte[] playerName2 = {0x4d, 0x75, 0x73, 0x69, 0x63, 0x32}/*Music2*/;
featureMasks[FEATURE_MASK_PLAY_OFFSET] =
featureMasks[FEATURE_MASK_PLAY_OFFSET] | FEATURE_MASK_PLAY_MASK;
@@ -514,27 +632,6 @@ public final class Avrcp {
featureMasks[FEATURE_MASK_BR_WH_ADDR_OFFSET] =
featureMasks[FEATURE_MASK_BR_WH_ADDR_OFFSET] | FEATURE_MASK_BR_WH_ADDR_MASK;
- /*Google player does not support browsing and now playing,
- hence updated the masks properly*/
- featureMasks2[FEATURE_MASK_PLAY_OFFSET] =
- featureMasks2[FEATURE_MASK_PLAY_OFFSET] | FEATURE_MASK_PLAY_MASK;
- featureMasks2[FEATURE_MASK_PAUSE_OFFSET] =
- featureMasks2[FEATURE_MASK_PAUSE_OFFSET] | FEATURE_MASK_PAUSE_MASK;
- featureMasks2[FEATURE_MASK_STOP_OFFSET] =
- featureMasks2[FEATURE_MASK_STOP_OFFSET] | FEATURE_MASK_STOP_MASK;
- featureMasks2[FEATURE_MASK_PAGE_UP_OFFSET] =
- featureMasks2[FEATURE_MASK_PAGE_UP_OFFSET] | FEATURE_MASK_PAGE_UP_MASK;
- featureMasks2[FEATURE_MASK_PAGE_DOWN_OFFSET] =
- featureMasks2[FEATURE_MASK_PAGE_DOWN_OFFSET] | FEATURE_MASK_PAGE_DOWN_MASK;
- featureMasks2[FEATURE_MASK_REWIND_OFFSET] =
- featureMasks2[FEATURE_MASK_REWIND_OFFSET] | FEATURE_MASK_REWIND_MASK;
- featureMasks2[FEATURE_MASK_FAST_FWD_OFFSET] =
- featureMasks2[FEATURE_MASK_FAST_FWD_OFFSET] | FEATURE_MASK_FAST_FWD_MASK;
- featureMasks2[FEATURE_MASK_VENDOR_OFFSET] =
- featureMasks2[FEATURE_MASK_VENDOR_OFFSET] | FEATURE_MASK_VENDOR_MASK;
- featureMasks2[FEATURE_MASK_ADV_CTRL_OFFSET] =
- featureMasks2[FEATURE_MASK_ADV_CTRL_OFFSET] | FEATURE_MASK_ADV_CTRL_MASK;
-
mediaPlayerInfo1 = new MediaPlayerInfo ((short)0x0001,
MAJOR_TYPE_AUDIO,
SUB_TYPE_NONE,
@@ -546,36 +643,31 @@ public final class Avrcp {
true,
featureMasks);
- mediaPlayerInfo2 = new MediaPlayerInfo ((short)0x0002,
- MAJOR_TYPE_AUDIO,
- SUB_TYPE_NONE,
- (byte)RemoteControlClient.PLAYSTATE_PAUSED,
- CHAR_SET_UTF8,
- (short)0x06,
- playerName2,
- "com.google.android.music",
- false,
- featureMasks2);
-
mMediaPlayers.add(mediaPlayerInfo1);
- mMediaPlayers.add(mediaPlayerInfo2);
}
- public static Avrcp make(Context context) {
- if (DEBUG) Log.v(TAG, "make");
- Avrcp ar = new Avrcp(context);
+ public static Avrcp make(Context context, A2dpService svc,
+ int maxConnections) {
+ if (DEBUG)
+ Log.v(TAG, "make");
+ Avrcp ar = new Avrcp(context, svc, maxConnections);
ar.start();
return ar;
}
public void doQuit() {
- if (DEBUG) Log.v(TAG, "doQuit");
+ if (DEBUG)
+ Log.v(TAG, "doQuit");
mHandler.removeCallbacksAndMessages(null);
Looper looper = mHandler.getLooper();
if (looper != null) {
looper.quit();
}
mAudioManager.unregisterRemoteController(mRemoteController);
+ clearDeviceDependentFeature();
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ cleanupDeviceFeaturesIndex(i);
+ }
try {
mContext.unregisterReceiver(mIntentReceiver);
}catch (Exception e) {
@@ -584,16 +676,25 @@ public final class Avrcp {
mMediaPlayers.clear();
if (mHandler.hasMessages(MESSAGE_SET_ADDR_PLAYER_REQ_TIMEOUT)) {
mHandler.removeMessages(MESSAGE_SET_ADDR_PLAYER_REQ_TIMEOUT);
- mRequestedAddressedPlayerPackageName = null;
- if (DEBUG) Log.v(TAG, "Addressed player message cleanup as part of doQuit");
+ if (DEBUG)
+ Log.v(TAG, "Addressed player message cleanup as part of doQuit");
+ }
+ }
+
+ public void clearDeviceDependentFeature() {
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ deviceFeatures[i].keyPressState = KEY_STATE_RELEASE; //Key release state
+ deviceFeatures[i].mCurrentPath = PATH_INVALID;
+ deviceFeatures[i].mMediaUri = Uri.EMPTY;
+ deviceFeatures[i].mCurrentPathUid = null;
+ deviceFeatures[i].mRequestedAddressedPlayerPackageName = null;
}
- mCurrentPath = PATH_INVALID;
- mMediaUri = Uri.EMPTY;
- mCurrentPathUid = null;
+
}
public void cleanup() {
- if (DEBUG) Log.v(TAG, "cleanup");
+ if (DEBUG)
+ Log.v(TAG, "cleanup");
cleanupNative();
}
@@ -682,7 +783,7 @@ public final class Avrcp {
for (int count = 0; count < SplitPath.length; count++) {
Log.v(TAG, "folderName: " + SplitPath[count]);
}
- mMediaUri = uri;
+ mMediaUriStatic = uri;
if (handler != null) {
handler.obtainMessage(MSG_UPDATE_BROWSED_PLAYER_FOLDER, NUM_ROOT_ELEMENTS,
SplitPath.length, SplitPath).sendToTarget();
@@ -723,7 +824,7 @@ public final class Avrcp {
}
}
- /** Handles Avrcp messages. */
+ /* Handles Avrcp messages. */
private final class AvrcpMessageHandler extends Handler {
private AvrcpMessageHandler(Looper looper) {
super(looper);
@@ -731,31 +832,43 @@ public final class Avrcp {
@Override
public void handleMessage(Message msg) {
+ int deviceIndex = INVALID_DEVICE_INDEX;
switch (msg.what) {
case MESSAGE_PLAYERSETTINGS_TIMEOUT:
- if (DEBUG) Log.v(TAG, "**MESSAGE_PLAYSTATUS_TIMEOUT");
+ Log.e(TAG, "**MESSAGE_PLAYSTATUS_TIMEOUT: Addr: " +
+ (String)msg.obj + " Msg: " + msg.arg1);
synchronized (mPendingCmds) {
- Integer val = new Integer(msg.arg1);
- if (!mPendingCmds.contains(val)) {
- break;
+ Integer val = new Integer(msg.arg1);
+ if (!mPendingCmds.contains(val)) {
+ break;
+ }
+ mPendingCmds.remove(val);
}
- mPendingCmds.remove(val);
- }
- switch (msg.arg1) {
+ switch (msg.arg1) {
case GET_ATTRIBUTE_IDS:
- getListPlayerappAttrRspNative((byte)def_attrib.length, def_attrib);
+ getListPlayerappAttrRspNative((byte)def_attrib.length ,
+ def_attrib, getByteAddress(
+ mAdapter.getRemoteDevice((String) msg.obj)));
break;
case GET_VALUE_IDS:
- if (DEBUG) Log.v(TAG, "GET_VALUE_IDS");
switch (mPlayerSettings.attr) {
case ATTRIBUTE_REPEATMODE:
- getPlayerAppValueRspNative((byte)value_repmode.length, value_repmode);
+ getPlayerAppValueRspNative((byte)value_repmode.length,
+ value_repmode,
+ getByteAddress(mAdapter.getRemoteDevice(
+ (String) msg.obj)));
break;
case ATTRIBUTE_SHUFFLEMODE:
- getPlayerAppValueRspNative((byte)value_shufmode.length, value_shufmode);
+ getPlayerAppValueRspNative((byte)value_shufmode.length,
+ value_shufmode,
+ getByteAddress(mAdapter.getRemoteDevice(
+ (String) msg.obj)));
break;
default:
- getPlayerAppValueRspNative((byte)value_default.length, value_default);
+ getPlayerAppValueRspNative((byte)value_default.length,
+ value_default,
+ getByteAddress(mAdapter.getRemoteDevice(
+ (String) msg.obj)));
break;
}
break;
@@ -772,32 +885,49 @@ public final class Avrcp {
retVal[j++] = 0x0;
}
}
- SendCurrentPlayerValueRspNative((byte)retVal.length, retVal);
+ SendCurrentPlayerValueRspNative((byte)retVal.length ,
+ retVal, getByteAddress(mAdapter.getRemoteDevice(
+ (String) msg.obj)));
break;
case SET_ATTRIBUTE_VALUES :
- SendSetPlayerAppRspNative(INTERNAL_ERROR);
+ SendSetPlayerAppRspNative(INTERNAL_ERROR, getByteAddress(
+ mAdapter.getRemoteDevice((String) msg.obj)));
break;
case GET_ATTRIBUTE_TEXT:
- case GET_VALUE_TEXT:
- String [] values = new String [mPlayerSettings.attrIds.length];
- String msgVal = (msg.what == GET_ATTRIBUTE_TEXT) ? UPDATE_ATTRIB_TEXT :
- UPDATE_VALUE_TEXT;
+ String [] attribText = new String [mPlayerSettings.attrIds.length];
for (int i = 0; i < mPlayerSettings.attrIds.length; i++) {
- values[i] = "";
+ attribText[i] = "";
}
sendSettingsTextRspNative(mPlayerSettings.attrIds.length ,
- mPlayerSettings.attrIds, values.length,values);
+ mPlayerSettings.attrIds, attribText.length,
+ attribText, getByteAddress(mAdapter.getRemoteDevice(
+ (String) msg.obj)));
+ break;
+ case GET_VALUE_TEXT:
+ String [] valueText = new String [mPlayerSettings.attrIds.length];
+ for (int i = 0; i < mPlayerSettings.attrIds.length; i++) {
+ valueText[i] = "";
+ }
+ sendValueTextRspNative(mPlayerSettings.attrIds.length ,
+ mPlayerSettings.attrIds, valueText.length,
+ valueText,getByteAddress(mAdapter.getRemoteDevice(
+ (String) msg.obj)));
break;
default :
+ Log.e(TAG,"in default case");
break;
}
break;
case MSG_UPDATE_STATE:
- updatePlayPauseState(msg.arg2, ((Long) msg.obj).longValue());
+ /* since we get this from music app we need to update
+ * current playing start time */
+ Log.i(TAG,"State change for music app");
+ updatePlayPauseState(msg.arg2, ((Long) msg.obj).longValue(),
+ null);
break;
case MSG_SET_METADATA:
- updateMetadata((MetadataEditor) msg.obj);
+ updateMetadata((MetadataEditor) msg.obj);
break;
case MSG_UPDATE_AVAILABLE_PLAYERS:
@@ -831,138 +961,264 @@ public final class Avrcp {
break;
case MSG_SET_TRANSPORT_CONTROLS:
- updateTransportControls(msg.arg2);
+ updateTransportControls(msg.arg2);
break;
case MSG_SET_GENERATION_ID:
- if (DEBUG) Log.v(TAG, "New genId = " + msg.arg1 + ", clearing = " + msg.arg2);
+ if (DEBUG)
+ Log.v(TAG, "New genId = " + msg.arg1 +
+ ", clearing = " + msg.arg2);
break;
case MESSAGE_GET_RC_FEATURES:
+ {
String address = (String) msg.obj;
- if (DEBUG) Log.v(TAG, "MESSAGE_GET_RC_FEATURES: address="+address+
- ", features="+msg.arg1);
- mFeatures = msg.arg1;
- mAudioManager.avrcpSupportsAbsoluteVolume(address, isAbsoluteVolumeSupported());
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_GET_RC_FEATURES: address="+address+
+ ", features="+msg.arg1);
+ BluetoothDevice device = mAdapter.getRemoteDevice(address);
+ deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.v(TAG,"device entry not present, bailing out");
+ return;
+ }
+ deviceFeatures[deviceIndex].mFeatures = msg.arg1;
+ deviceFeatures[deviceIndex].isAbsoluteVolumeSupportingDevice =
+ ((deviceFeatures[deviceIndex].mFeatures &
+ BTRC_FEAT_ABSOLUTE_VOLUME) != 0);
+ mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(),
+ isAbsoluteVolumeSupported());
+ Log.v(TAG," update audio manager for abs vol state = "
+ + isAbsoluteVolumeSupported());
break;
-
+ }
case MESSAGE_GET_PLAY_STATUS:
- if (DEBUG) Log.v(TAG, "MESSAGE_GET_PLAY_STATUS");
- long playPosition = getPlayPosition();
- if (playPosition == -1L) {
+ {
+ BluetoothDevice device;
+ int playState, position;
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_GET_PLAY_STATUS");
+ Log.v(TAG, "Event for device address " + (String)msg.obj);
+
+ device = mAdapter.getRemoteDevice((String) msg.obj);
+ deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"Invalid device index for play status");
+ break;
+ }
+ playState = convertPlayStateToPlayStatus(deviceFeatures[deviceIndex].mCurrentPlayState);
+ position = (int)getPlayPosition(device);
+ Log.v(TAG, "Play Status for : " + device.getName() +
+ " state: " + playState + " position: " + position);
+ if (position == -1) {
Log.v(TAG, "Force play postion to 0, for getPlayStatus Rsp");
- playPosition = 0L;
+ position = 0;
}
- getPlayStatusRspNative(convertPlayStateToPlayStatus(mCurrentPlayState),
- (int)mSongLengthMs, (int)playPosition);
- break;
+ getPlayStatusRspNative(playState, (int)mSongLengthMs, position,
+ getByteAddress(device));
+ break;
+ }
case MESSAGE_GET_ELEM_ATTRS:
{
String[] textArray;
int[] attrIds;
byte numAttr = (byte) msg.arg1;
- ArrayList<Integer> attrList = (ArrayList<Integer>) msg.obj;
- if (DEBUG) Log.v(TAG, "MESSAGE_GET_ELEM_ATTRS:numAttr=" + numAttr);
+ ItemAttr itemAttr = (ItemAttr)msg.obj;
+ Log.v(TAG, "event for device address " + itemAttr.mAddress);
+ ArrayList<Integer> attrList = itemAttr.mAttrList;
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_GET_ELEM_ATTRS:numAttr=" + numAttr);
attrIds = new int[numAttr];
textArray = new String[numAttr];
for (int i = 0; i < numAttr; ++i) {
attrIds[i] = attrList.get(i).intValue();
textArray[i] = getAttributeString(attrIds[i]);
}
- getElementAttrRspNative(numAttr, attrIds, textArray);
+ getElementAttrRspNative(numAttr ,attrIds ,textArray ,
+ getByteAddress(mAdapter.getRemoteDevice(itemAttr.mAddress)));
break;
}
case MESSAGE_REGISTER_NOTIFICATION:
- if (DEBUG) Log.v(TAG, "MESSAGE_REGISTER_NOTIFICATION:event=" + msg.arg1 +
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_REGISTER_NOTIFICATION:event=" + msg.arg1 +
" param=" + msg.arg2);
- processRegisterNotification(msg.arg1, msg.arg2);
+ processRegisterNotification(msg.arg1, msg.arg2, (String) msg.obj);
break;
case MESSAGE_PLAY_INTERVAL_TIMEOUT:
- if (DEBUG) Log.v(TAG, "MESSAGE_PLAY_INTERVAL_TIMEOUT");
- mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
- registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)getPlayPosition());
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_PLAY_INTERVAL_TIMEOUT");
+ Log.v(TAG, "event for device address " + (BluetoothDevice)msg.obj);
+ deviceIndex = getIndexForDevice((BluetoothDevice) msg.obj);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ break;
+ }
+ deviceFeatures[deviceIndex].mPlayPosChangedNT =
+ NOTIFICATION_TYPE_CHANGED;
+ Log.v(TAG, "event for device address " + (BluetoothDevice) msg.obj);
+ registerNotificationRspPlayPosNative(deviceFeatures[deviceIndex].mPlayPosChangedNT,
+ (int)getPlayPosition((BluetoothDevice) msg.obj) ,
+ getByteAddress((BluetoothDevice) msg.obj));
break;
case MESSAGE_SET_ADDR_PLAYER_REQ_TIMEOUT:
- if (DEBUG) Log.v(TAG, "setAddressedPlayer fails, Times out");
- setAdressedPlayerRspNative ((byte)PLAYER_NOT_ADDRESSED);
- mRequestedAddressedPlayerPackageName = null;
+ if (DEBUG)
+ Log.v(TAG, "setAddressedPlayer fails, Times out");
+ deviceIndex = getIndexForDevice(mAdapter.getRemoteDevice((String) msg.obj));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid device index");
+ break;
+ }
+ Log.v(TAG, "event for device address " + (String)msg.obj);
+ setAdressedPlayerRspNative((byte)PLAYER_NOT_ADDRESSED,
+ getByteAddress(mAdapter.getRemoteDevice((String) msg.obj)));
+ deviceFeatures[deviceIndex].mRequestedAddressedPlayerPackageName = null;
break;
case MESSAGE_VOLUME_CHANGED:
- if (DEBUG) Log.v(TAG, "MESSAGE_VOLUME_CHANGED: volume=" + ((byte)msg.arg1 & 0x7f)
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_VOLUME_CHANGED: volume=" + ((byte)msg.arg1 & 0x7f)
+ " ctype=" + msg.arg2);
-
+ Log.v(TAG, "event for device address " + (String)msg.obj);
+ deviceIndex = getIndexForDevice(mAdapter.getRemoteDevice((String) msg.obj));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ break;
+ }
if (msg.arg2 == AVRC_RSP_ACCEPT || msg.arg2 == AVRC_RSP_REJ) {
- if (mVolCmdInProgress == false) {
+ if (deviceFeatures[deviceIndex].mVolCmdInProgress == false) {
Log.e(TAG, "Unsolicited response, ignored");
break;
}
removeMessages(MESSAGE_ABS_VOL_TIMEOUT);
- mVolCmdInProgress = false;
- mAbsVolRetryTimes = 0;
+ deviceFeatures[deviceIndex].mVolCmdInProgress = false;
+ deviceFeatures[deviceIndex].mAbsVolRetryTimes = 0;
}
- if (mAbsoluteVolume != msg.arg1 && (msg.arg2 == AVRC_RSP_ACCEPT ||
- msg.arg2 == AVRC_RSP_CHANGED ||
- msg.arg2 == AVRC_RSP_INTERIM)) {
+ if (deviceFeatures[deviceIndex].mAbsoluteVolume != msg.arg1 &&
+ (msg.arg2 == AVRC_RSP_ACCEPT ||
+ msg.arg2 == AVRC_RSP_CHANGED ||
+ msg.arg2 == AVRC_RSP_INTERIM)) {
byte absVol = (byte)((byte)msg.arg1 & 0x7f); // discard MSB as it is RFD
- notifyVolumeChanged(absVol);
- mAbsoluteVolume = absVol;
+ deviceFeatures[deviceIndex].mAbsoluteVolume = absVol;
long pecentVolChanged = ((long)absVol * 100) / 0x7f;
- Log.e(TAG, "percent volume changed: " + pecentVolChanged + "%");
+ Log.v(TAG, "Absolute Volume change received as: " + absVol);
+ Log.v(TAG, "Percent volume changed: " + pecentVolChanged + "%");
+ if (isAbsoluteVolumeSupported() &&
+ deviceFeatures[deviceIndex].mAbsoluteVolume != -1) {
+ Log.v(TAG," update audio manager for absolute volume = "
+ + deviceFeatures[deviceIndex].mAbsoluteVolume);
+ notifyVolumeChanged(deviceFeatures[deviceIndex].mAbsoluteVolume,
+ deviceFeatures[deviceIndex].mCurrentDevice);
+ }
} else if (msg.arg2 == AVRC_RSP_REJ) {
- Log.e(TAG, "setAbsoluteVolume call rejected");
+ if (DEBUG)
+ Log.v(TAG, "setAbsoluteVolume call rejected");
}
break;
case MESSAGE_ADJUST_VOLUME:
- if (DEBUG) Log.d(TAG, "MESSAGE_ADJUST_VOLUME: direction=" + msg.arg1);
- if (mVolCmdInProgress) {
- if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
- break;
- }
- // Wait on verification on volume from device, before changing the volume.
- if (mAbsoluteVolume != -1 && (msg.arg1 == -1 || msg.arg1 == 1)) {
- int setVol = Math.min(AVRCP_MAX_VOL,
- Math.max(0, mAbsoluteVolume + msg.arg1*mVolumeStep));
- if (setVolumeNative(setVol)) {
- sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
- CMD_TIMEOUT_DELAY);
- mVolCmdInProgress = true;
- mLastDirection = msg.arg1;
- mLastSetVolume = setVol;
+ {
+ List<BluetoothDevice> playingDevice = mA2dpService.getA2dpPlayingDevice();
+ if (DEBUG)
+ Log.d(TAG, "MESSAGE_ADJUST_VOLUME: direction=" + msg.arg1);
+ for (int i = 0; i < playingDevice.size(); i++) {
+ Log.v(TAG, "event for device address " +
+ playingDevice.get(i).getAddress());
+ deviceIndex = getIndexForDevice(playingDevice.get(i));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"Unkown playing device");
+ sendAdjustVolume(msg.arg1);
+ continue;
+ }
+ if (deviceFeatures[deviceIndex].mVolCmdInProgress) {
+ if (DEBUG)
+ Log.w(TAG, "already a volume command in progress" +
+ "for this device.");
+ continue;
+ }
+ // Wait on verification on volume from device, before changing the volume.
+ if (deviceFeatures[deviceIndex].mAbsoluteVolume != -1 &&
+ (msg.arg1 == -1 || msg.arg1 == 1)) {
+ int setVol = Math.min(AVRCP_MAX_VOL,
+ Math.max(0, deviceFeatures[deviceIndex].mAbsoluteVolume +
+ msg.arg1*mVolumeStep));
+ boolean isSetVol = setVolumeNative(setVol ,
+ getByteAddress(playingDevice.get(i)));
+ if (isSetVol) {
+ sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT,
+ 0, 0, deviceFeatures[deviceIndex].mCurrentDevice),
+ CMD_TIMEOUT_DELAY);
+ deviceFeatures[deviceIndex].mVolCmdInProgress = true;
+ deviceFeatures[deviceIndex].mLastDirection = msg.arg1;
+ deviceFeatures[deviceIndex].mLastSetVolume = setVol;
+ }
+ } else {
+ Log.e(TAG, "Unknown direction in MESSAGE_ADJUST_VOLUME");
}
- } else {
- Log.e(TAG, "Unknown direction in MESSAGE_ADJUST_VOLUME");
}
break;
-
+ }
case MESSAGE_SET_ABSOLUTE_VOLUME:
- if (DEBUG) Log.v(TAG, "MESSAGE_SET_ABSOLUTE_VOLUME");
- if (mVolCmdInProgress) {
- if (DEBUG) Log.w(TAG, "There is already a volume command in progress.");
- break;
+ {
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_SET_ABSOLUTE_VOLUME");
+ List<BluetoothDevice> playingDevice = mA2dpService.getA2dpPlayingDevice();
+ if (playingDevice.size() == 0) {
+ Log.e(TAG,"Volume cmd without a2dp playing");
}
- if (setVolumeNative(msg.arg1)) {
- sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT), CMD_TIMEOUT_DELAY);
- mVolCmdInProgress = true;
- mLastSetVolume = msg.arg1;
+ for (int i = 0; i < playingDevice.size(); i++) {
+ deviceIndex = getIndexForDevice(playingDevice.get(i));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"Unkown playing device");
+ sendSetAbsoluteVolume(msg.arg1);
+ continue;
+ }
+ Log.v(TAG, "event for device address " +
+ playingDevice.get(i).getAddress());
+ if (deviceFeatures[deviceIndex].mVolCmdInProgress) {
+ if (DEBUG)
+ Log.w(TAG, "There is already a volume command in progress.");
+ continue;
+ }
+ Log.v(TAG, "event for device address " + (String)msg.obj);
+ boolean isSetVol = setVolumeNative(msg.arg1 ,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ if (isSetVol) {
+ sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT,
+ 0, 0, deviceFeatures[deviceIndex].mCurrentDevice),
+ CMD_TIMEOUT_DELAY);
+ deviceFeatures[deviceIndex].mVolCmdInProgress = true;
+ deviceFeatures[deviceIndex].mLastSetVolume = msg.arg1;
+ }
}
break;
-
+ }
case MESSAGE_ABS_VOL_TIMEOUT:
- if (DEBUG) Log.v(TAG, "MESSAGE_ABS_VOL_TIMEOUT: Volume change cmd timed out.");
- mVolCmdInProgress = false;
- if (mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) {
- mAbsVolRetryTimes = 0;
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_ABS_VOL_TIMEOUT: Volume change cmd timed out.");
+ deviceIndex = getIndexForDevice((BluetoothDevice) msg.obj);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid device index for abs vol timeout");
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mVolCmdInProgress == true)
+ deviceFeatures[i].mVolCmdInProgress = false;
+ }
+ break;
+ }
+ deviceFeatures[deviceIndex].mVolCmdInProgress = false;
+ Log.v(TAG, "event for device address " + (BluetoothDevice)msg.obj);
+ if (deviceFeatures[deviceIndex].mAbsVolRetryTimes >= MAX_ERROR_RETRY_TIMES) {
+ deviceFeatures[deviceIndex].mAbsVolRetryTimes = 0;
} else {
- mAbsVolRetryTimes += 1;
- if (setVolumeNative(mLastSetVolume)) {
- sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT),
- CMD_TIMEOUT_DELAY);
- mVolCmdInProgress = true;
+ deviceFeatures[deviceIndex].mAbsVolRetryTimes += 1;
+ boolean isSetVol = setVolumeNative(deviceFeatures[deviceIndex].mLastSetVolume ,
+ getByteAddress((BluetoothDevice) msg.obj));
+ if (isSetVol) {
+ sendMessageDelayed(obtainMessage(MESSAGE_ABS_VOL_TIMEOUT,
+ 0, 0, msg.obj), CMD_TIMEOUT_DELAY);
+ deviceFeatures[deviceIndex].mVolCmdInProgress = true;
}
}
break;
@@ -991,11 +1247,13 @@ public final class Avrcp {
int skipAmount;
if (msg.what == MESSAGE_FAST_FORWARD) {
- if (DEBUG) Log.v(TAG, "MESSAGE_FAST_FORWARD");
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_FAST_FORWARD");
removeMessages(MESSAGE_FAST_FORWARD);
skipAmount = BASE_SKIP_AMOUNT;
} else {
- if (DEBUG) Log.v(TAG, "MESSAGE_REWIND");
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_REWIND");
removeMessages(MESSAGE_REWIND);
skipAmount = -BASE_SKIP_AMOUNT;
}
@@ -1013,8 +1271,10 @@ public final class Avrcp {
removeMessages(MESSAGE_CHANGE_PLAY_POS);
if (msg.arg1 == KEY_STATE_PRESS) {
mSkipAmount = skipAmount;
- changePositionBy(mSkipAmount * getSkipMultiplier());
- Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS);
+ changePositionBy(mSkipAmount * getSkipMultiplier(),
+ (String)msg.obj);
+ Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS,
+ 0, 0, msg.obj);
posMsg.arg1 = 1;
sendMessageDelayed(posMsg, SKIP_PERIOD);
}
@@ -1022,18 +1282,31 @@ public final class Avrcp {
break;
case MESSAGE_CHANGE_PLAY_POS:
- if (DEBUG) Log.v(TAG, "MESSAGE_CHANGE_PLAY_POS:" + msg.arg1);
- changePositionBy(mSkipAmount * getSkipMultiplier());
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_CHANGE_PLAY_POS:" + msg.arg1);
+ changePositionBy(mSkipAmount * getSkipMultiplier(),
+ (String)msg.obj);
if (msg.arg1 * SKIP_PERIOD < BUTTON_TIMEOUT_TIME) {
- Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS);
+ Message posMsg = obtainMessage(MESSAGE_CHANGE_PLAY_POS,
+ 0, 0, msg.obj);
posMsg.arg1 = msg.arg1 + 1;
sendMessageDelayed(posMsg, SKIP_PERIOD);
}
break;
case MESSAGE_SET_A2DP_AUDIO_STATE:
- if (DEBUG) Log.v(TAG, "MESSAGE_SET_A2DP_AUDIO_STATE:" + msg.arg1);
- updateA2dpAudioState(msg.arg1);
+ if (DEBUG)
+ Log.v(TAG, "MESSAGE_SET_A2DP_AUDIO_STATE:" + msg.arg1);
+ BluetoothDevice playStateChangeDevice =
+ (BluetoothDevice)msg.obj;
+ Log.v(TAG, "event for device address " +
+ playStateChangeDevice.getAddress());
+ deviceIndex = getIndexForDevice(playStateChangeDevice);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"in valid index for device");
+ break;
+ }
+ updateA2dpAudioState(msg.arg1, (BluetoothDevice)msg.obj);
break;
case MSG_UPDATE_RCC_CHANGE:
@@ -1045,25 +1318,28 @@ public final class Avrcp {
break;
case MESSAGE_SET_ADDR_PLAYER:
- processSetAddressedPlayer(msg.arg1);
+ processSetAddressedPlayer(msg.arg1, (String) msg.obj);
break;
case MESSAGE_SET_BROWSED_PLAYER:
- processSetBrowsedPlayer(msg.arg1);
+ processSetBrowsedPlayer(msg.arg1, (String) msg.obj);
break;
case MESSAGE_CHANGE_PATH:
- processChangePath(msg.arg1, ((Long)msg.obj).longValue());
+ ItemAttr itemAttr = (ItemAttr)msg.obj;
+ processChangePath(msg.arg1, itemAttr.mUid, itemAttr.mAddress);
break;
case MESSAGE_PLAY_ITEM:
- processPlayItem(msg.arg1, ((Long)msg.obj).longValue());
+ itemAttr = (ItemAttr)msg.obj;
+ processPlayItem(msg.arg1, itemAttr.mUid, itemAttr.mAddress);
break;
case MESSAGE_GET_ITEM_ATTRS:
int[] attrIds;
- ItemAttr itemAttr = (ItemAttr)msg.obj;
+ itemAttr = (ItemAttr)msg.obj;
attrIds = new int[msg.arg1];
for (int i = 0; i < msg.arg1; ++i) {
attrIds[i] = itemAttr.mAttrList.get(i).intValue();
}
- processGetItemAttr((byte)msg.arg2, itemAttr.mUid, (byte)msg.arg1, attrIds);
+ processGetItemAttr((byte)msg.arg2, itemAttr.mUid, (byte)msg.arg1,
+ attrIds, itemAttr.mAddress);
break;
case MESSAGE_GET_FOLDER_ITEMS:
FolderListEntries folderListEntries = (FolderListEntries)msg.obj;
@@ -1073,111 +1349,261 @@ public final class Avrcp {
}
processGetFolderItems(folderListEntries.mScope, folderListEntries.mStart,
folderListEntries.mEnd, folderListEntries.mAttrCnt,
- folderListEntries.mNumAttr, attrIds);
+ folderListEntries.mNumAttr, attrIds, folderListEntries.mAddress);
break;
}
}
}
- private void updateA2dpAudioState(int state) {
- boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING);
- if (isPlaying != isPlayingState(mCurrentPlayState)) {
- /* if a2dp is streaming, check to make sure music is active */
- if ( (isPlaying) && !mAudioManager.isMusicActive())
- return;
- updatePlayPauseState(isPlaying ? RemoteControlClient.PLAYSTATE_PLAYING :
- RemoteControlClient.PLAYSTATE_PAUSED,
- RemoteControlClient.PLAYBACK_POSITION_INVALID);
+ private void sendAdjustVolume(int val) {
+ Log.v(TAG, "in sendAdjustVolume" + " " + val);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mCurrentDevice != null &&
+ ((deviceFeatures[i].mFeatures &
+ BTRC_FEAT_ABSOLUTE_VOLUME) != 0)) {
+ if (deviceFeatures[i].mAbsoluteVolume != -1 &&
+ (val == -1 || val == 1)) {
+ int setVol = Math.min(AVRCP_MAX_VOL,
+ Math.max(0, deviceFeatures[i].mAbsoluteVolume +
+ val*mVolumeStep));
+ boolean isSetVol = setVolumeNative(setVol ,
+ getByteAddress((deviceFeatures[i].mCurrentDevice)));
+ if (isSetVol) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ABS_VOL_TIMEOUT,
+ 0, 0, deviceFeatures[i].mCurrentDevice),
+ CMD_TIMEOUT_DELAY);
+ deviceFeatures[i].mVolCmdInProgress = true;
+ deviceFeatures[i].mLastDirection = val;
+ deviceFeatures[i].mLastSetVolume = setVol;
+ }
+ } else {
+ Log.e(TAG, "Unknown direction in MESSAGE_ADJUST_VOLUME");
+ }
+ }
}
}
- private void updatePlayPauseState(int state, long currentPosMs) {
- if (DEBUG) Log.v(TAG,
- "updatePlayPauseState, old=" + mCurrentPlayState + ", state=" + state);
- boolean oldPosValid = (mCurrentPosMs !=
- RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN);
- if (state == RemoteControlClient.PLAYSTATE_PLAYING) { // may be change in player
- if (mMediaPlayers.size() > 0) {
- final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
- while (rccIterator.hasNext()) {
- final MediaPlayerInfo di = rccIterator.next();
- if (di.GetPlayerFocus()) { // may be change in player, update with player specific state
- if (DEBUG) Log.v(TAG, "reset " + di.getPlayerPackageName() + " playbackState as: " + di.GetPlayState());
- mCurrentPlayState = di.GetPlayState();
- break;
- }
+ private void sendSetAbsoluteVolume(int val) {
+ Log.v(TAG, "in sendSetAbsoluteVolume " + " " + val);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mCurrentDevice != null &&
+ ((deviceFeatures[i].mFeatures &
+ BTRC_FEAT_ABSOLUTE_VOLUME) != 0)) {
+ Log.v(TAG, "in sending for device " + deviceFeatures[i].mCurrentDevice);
+ boolean isSetVol = setVolumeNative(val ,
+ getByteAddress((deviceFeatures[i].mCurrentDevice)));
+ if (isSetVol) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ABS_VOL_TIMEOUT,
+ 0, 0, deviceFeatures[i].mCurrentDevice),
+ CMD_TIMEOUT_DELAY);
+ deviceFeatures[i].mVolCmdInProgress = true;
+ deviceFeatures[i].mLastSetVolume = val;
}
}
}
- if (DEBUG) Log.v(TAG, "old state = " + mCurrentPlayState + ", new state= " + state);
- int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayState);
+ }
+
+ private void updateA2dpAudioState(int state, BluetoothDevice device) {
+ boolean isPlaying = (state == BluetoothA2dp.STATE_PLAYING);
+
+ Log.v(TAG,"updateA2dpAudioState");
+ if ((isPlaying) && !mAudioManager.isMusicActive()) {
+ /* Play state to be updated only for music streaming, not touchtone */
+ Log.v(TAG,"updateA2dpAudioState: Stream state not active ");
+ return;
+ }
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if ((isPlaying != isPlayingState(deviceFeatures[i].mCurrentPlayState)) &&
+ (device.equals(deviceFeatures[i].mCurrentDevice))) {
+ updatePlayPauseState(isPlaying ? RemoteControlClient.PLAYSTATE_PLAYING :
+ RemoteControlClient.PLAYSTATE_PAUSED,
+ RemoteControlClient.PLAYBACK_POSITION_INVALID,
+ device);
+ break;
+ }
+ }
+ }
+
+ private void updateResetNotificationForDevice(BluetoothDevice device, int index) {
+ Log.i(TAG,"in updateResetNotificationForDevice " + device + " index " +
+ index);
+ if (deviceFeatures[index].mPlayPosChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) {
+ if (DEBUG)
+ Log.v(TAG, "send Play Position reject to stack");
+ deviceFeatures[index].mPlayPosChangedNT =
+ NOTIFICATION_TYPE_REJECT;
+ registerNotificationRspPlayPosNative(deviceFeatures[index].mPlayPosChangedNT,
+ -1 ,getByteAddress(device));
+ mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
+ } else {
+ Log.v(TAG,"index " + index + " status is"+
+ deviceFeatures[index].mPlayPosChangedNT);
+ }
+ }
+
+ private void updatePlayPauseState(int state, long currentPosMs,
+ BluetoothDevice device) {
+ Log.v(TAG,"updatePlayPauseState, state: " + state + " device: " + device);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ Log.v(TAG,"Device: " + ((deviceFeatures[i].mCurrentDevice == null) ?
+ "no name: " : deviceFeatures[i].mCurrentDevice.getName() +
+ " : old state: " + deviceFeatures[i].mCurrentPlayState));
+ }
+ if (device == null) {
+ /*Called because of player state change*/
+ updatePlayerStateAndPosition(state, currentPosMs);
+ return;
+ } else {
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.w(TAG,"invalid device index" +
+ "Play status change for not connected device");
+ } else {
+ Log.v(TAG, "old state: " + deviceFeatures[deviceIndex].mCurrentPlayState
+ + " new state: " + state + " device: " +
+ device + " index: " + deviceIndex);
+ updatePlayStatusForDevice(deviceIndex, state);
+ }
+ }
+ }
+
+ private void updatePlayStatusForDevice(int deviceIndex,int state) {
+ Log.i(TAG,"updatePlayStatusForDevice");
+ int oldPlayStatus = convertPlayStateToPlayStatus(
+ deviceFeatures[deviceIndex].mCurrentPlayState);
+ int newPlayStatus = convertPlayStateToPlayStatus(state);
+ if (DEBUG)
+ Log.v(TAG, "oldPlayStatus " + oldPlayStatus);
+ if (DEBUG)
+ Log.v(TAG, "newPlayStatus " + newPlayStatus);
+
+ deviceFeatures[deviceIndex].mCurrentPlayState = state;
+
+ if ((deviceFeatures[deviceIndex].mPlayStatusChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) && (oldPlayStatus != newPlayStatus)) {
+ deviceFeatures[deviceIndex].mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
+ registerNotificationRspPlayStatusNative(
+ deviceFeatures[deviceIndex].mPlayStatusChangedNT,
+ newPlayStatus,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ }
+ }
+
+ private void updatePlayerStateAndPosition(int state, long currentPosMs) {
+ if (DEBUG) Log.v(TAG, "updatePlayerPlayPauseState, old=" +
+ mCurrentPlayerState + ", state=" + state);
+ boolean oldPosValid = (mCurrentPosMs !=
+ RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN);
+
+ if (DEBUG) Log.v(TAG, "old state = " + mCurrentPlayerState + ", new state= " + state);
+ int oldPlayStatus = convertPlayStateToPlayStatus(mCurrentPlayerState);
int newPlayStatus = convertPlayStateToPlayStatus(state);
- if ((mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) &&
- (mCurrentPlayState != state) && oldPosValid) {
- mCurrentPosMs = getPlayPosition();
+ if ((mCurrentPlayerState == RemoteControlClient.PLAYSTATE_PLAYING) &&
+ (mCurrentPlayerState != state) && oldPosValid) {
+ mCurrentPosMs = getPlayPosition(null);
+ Log.d(TAG, "Update mCurrentPosMs to " + mCurrentPosMs);
}
- if ((state == RemoteControlClient.PLAYSTATE_PLAYING) && (mCurrentPlayState != state)) {
+ if ((state == RemoteControlClient.PLAYSTATE_PLAYING) && (mCurrentPlayerState != state)) {
mPlayStartTimeMs = SystemClock.elapsedRealtime();
Log.d(TAG, "Update mPlayStartTimeMs to " + mPlayStartTimeMs);
}
- mCurrentPlayState = state;
-
- if (mMediaPlayers.size() > 0) {
- final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
- while (rccIterator.hasNext()) {
- final MediaPlayerInfo di = rccIterator.next();
- if (state == RemoteControlClient.PLAYSTATE_PLAYING) {
- if (di.GetPlayerFocus()) { // may be change in player, update player specific variables
- if (DEBUG) Log.v(TAG, "update " + di.getPlayerPackageName() + " playbackState as: " + mCurrentPlayState);
- di.SetPlayState((byte)mCurrentPlayState);
- } else { // reset the other players state as paused (default state)
- if (DEBUG) Log.v(TAG, "update " + di.getPlayerPackageName() + " playbackState as: Paused");
- di.SetPlayState((byte)RemoteControlClient.PLAYSTATE_PAUSED);
- }
- } else {
- if (di.GetPlayerFocus()) {
- if (DEBUG) Log.v(TAG, "update " + di.getPlayerPackageName() + " playbackState as: " + mCurrentPlayState);
- di.SetPlayState((byte)mCurrentPlayState);
- break;
- }
- }
- }
- }
+ mCurrentPlayerState = state;
- if (!(RemoteControlClient.PLAYSTATE_PLAYING == mCurrentPlayState &&
- mCurrentPlayState == state && mCurrentPosMs == currentPosMs)) {
+ if (!(RemoteControlClient.PLAYSTATE_PLAYING == mCurrentPlayerState
+ && mCurrentPosMs == currentPosMs)) {
if (currentPosMs != RemoteControlClient.PLAYBACK_POSITION_INVALID) {
mCurrentPosMs = currentPosMs;
mPlayStartTimeMs = SystemClock.elapsedRealtime();
- Log.d(TAG, "Update mPlayStartTimeMs: " + mPlayStartTimeMs + " mCurrentPosMs: "
- + mCurrentPosMs);
+ Log.d(TAG, "Update mPlayStartTimeMs: " + mPlayStartTimeMs +
+ " mCurrentPosMs: " + mCurrentPosMs);
}
}
boolean newPosValid = (mCurrentPosMs !=
RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN);
- long playPosition = getPlayPosition();
+ long playPosition = getPlayPosition(null);
mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
- /* need send play position changed notification when play status is changed */
- if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) &&
- ((oldPlayStatus != newPlayStatus) || (oldPosValid != newPosValid) ||
- (newPosValid && ((playPosition >= mNextPosMs) || (playPosition <= mPrevPosMs))))) {
- mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
- registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)playPosition);
+ for (int deviceIndex = 0; deviceIndex < maxAvrcpConnections; deviceIndex++) {
+ if (deviceFeatures[deviceIndex].mCurrentDevice != null &&
+ ((deviceFeatures[deviceIndex].mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) &&
+ ((oldPlayStatus != newPlayStatus) || (oldPosValid != newPosValid) ||
+ (newPosValid && ((playPosition >= deviceFeatures[deviceIndex].mNextPosMs) ||
+ (playPosition <= deviceFeatures[deviceIndex].mPrevPosMs)))))) {
+ deviceFeatures[deviceIndex].mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
+ registerNotificationRspPlayPosNative(deviceFeatures[deviceIndex].mPlayPosChangedNT,
+ (int)playPosition,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ }
+ if (deviceFeatures[deviceIndex].mCurrentDevice != null &&
+ ((deviceFeatures[deviceIndex].mPlayPosChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) && newPosValid &&
+ (state == RemoteControlClient.PLAYSTATE_PLAYING))) {
+ Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT,
+ 0, 0, deviceFeatures[deviceIndex].mCurrentDevice);
+ mHandler.sendMessageDelayed(msg, deviceFeatures[deviceIndex].mNextPosMs
+ - playPosition);
+ }
+ /*Discretion is required only when updating play state changed as playing*/
+ if ((state != RemoteControlClient.PLAYSTATE_PLAYING) ||
+ isPlayStateToBeUpdated(deviceIndex)) {
+ updatePlayStatusForDevice(deviceIndex, state);
+ }
}
- if ((mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) && newPosValid &&
- (state == RemoteControlClient.PLAYSTATE_PLAYING)) {
- Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
- mHandler.sendMessageDelayed(msg, mNextPosMs - playPosition);
+ }
+
+ private boolean isPlayStateToBeUpdated(int deviceIndex) {
+ Log.v(TAG, "isPlayStateTobeUpdated: device: " +
+ deviceFeatures[deviceIndex].mCurrentDevice);
+ if (maxAvrcpConnections < 2) {
+ Log.v(TAG, "maxAvrcpConnections: " + maxAvrcpConnections);
+ return true;
+ } else if(mA2dpService.isMulticastFeatureEnabled()) {
+ if (!areMultipleDevicesConnected()) {
+ Log.v(TAG, "Single connection exists");
+ return true;
+ } else if (mA2dpService.isMulticastEnabled()) {
+ Log.v(TAG, "Multicast is Enabled");
+ return true;
+ } else {
+ Log.v(TAG, "Multiple connection exists, Multicast not enabled");
+ if(isDeviceActiveInHandOffNative(getByteAddress(
+ deviceFeatures[deviceIndex].mCurrentDevice))) {
+ Log.v(TAG, "Device Active in handoff scenario");
+ return true;
+ } else {
+ Log.v(TAG, "Device Not Active in handoff scenario");
+ return false;
+ }
+ }
+ } else {
+ if (!areMultipleDevicesConnected()) {
+ Log.v(TAG, "Single connection exists");
+ return true;
+ } else {
+ Log.v(TAG, "Multiple connection exists in handoff");
+ if(isDeviceActiveInHandOffNative(getByteAddress(
+ deviceFeatures[deviceIndex].mCurrentDevice))) {
+ Log.v(TAG, "Device Active in handoff scenario");
+ return true;
+ } else {
+ Log.v(TAG, "Device Not Active in handoff scenario");
+ return false;
+ }
+ }
}
+ }
- if ((mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) && (oldPlayStatus != newPlayStatus)) {
- mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
- registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, newPlayStatus);
+ private boolean areMultipleDevicesConnected() {
+ for (int deviceIndex = 0; deviceIndex < maxAvrcpConnections; deviceIndex++) {
+ if (deviceFeatures[deviceIndex].mCurrentDevice == null) {
+ return false;
+ }
}
+ return true;
}
private void updateTransportControls(int transportControlFlags) {
@@ -1185,93 +1611,199 @@ public final class Avrcp {
}
private void updateAvailableMediaPlayers() {
- if (DEBUG) Log.v(TAG, "updateAvailableMediaPlayers");
- if (mAvailablePlayersChangedNT == NOTIFICATION_TYPE_INTERIM) {
- mAvailablePlayersChangedNT = NOTIFICATION_TYPE_CHANGED;
- if (DEBUG) Log.v(TAG, "send AvailableMediaPlayers to stack");
- registerNotificationRspAvailablePlayersChangedNative(mAvailablePlayersChangedNT);
+ /* for registerged notification check for all devices which has
+ * registered for change notification */
+ if (DEBUG)
+ Log.v(TAG, "updateAvailableMediaPlayers");
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mAvailablePlayersChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) {
+ deviceFeatures[i].mAvailablePlayersChangedNT = NOTIFICATION_TYPE_CHANGED;
+ if (DEBUG)
+ Log.v(TAG, "send AvailableMediaPlayers to stack");
+ registerNotificationRspAvailablePlayersChangedNative(
+ deviceFeatures[i].mAvailablePlayersChangedNT,
+ getByteAddress(deviceFeatures[i].mCurrentDevice));
+ }
}
}
private void updateAddressedMediaPlayer(int playerId) {
- if (DEBUG) Log.v(TAG, "updateAddressedMediaPlayer");
- int previousAddressedPlayerId = mAddressedPlayerId;
- if ((mAddressedPlayerChangedNT == NOTIFICATION_TYPE_INTERIM) && (mAddressedPlayerId != playerId)) {
- if (DEBUG) Log.v(TAG, "send AddressedMediaPlayer to stack: playerId" + playerId);
- mAddressedPlayerId = playerId;
- mAddressedPlayerChangedNT = NOTIFICATION_TYPE_CHANGED;
- registerNotificationRspAddressedPlayerChangedNative(mAddressedPlayerChangedNT, mAddressedPlayerId);
- if (previousAddressedPlayerId != 0) {
- resetAndSendPlayerStatusReject();
+ Log.v(TAG, "updateAddressedMediaPlayer");
+ Log.v(TAG, "current Player: " + mAddressedPlayerId);
+ Log.v(TAG, "Requested Player: " + playerId);
+
+ int previousAddressedPlayerId;
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if ((deviceFeatures[i].mAddressedPlayerChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) &&
+ (mAddressedPlayerId != playerId)) {
+ if (DEBUG)
+ Log.v(TAG, "send AddressedMediaPlayer to stack: playerId" + playerId);
+ previousAddressedPlayerId = mAddressedPlayerId;
+ deviceFeatures[i].mAddressedPlayerChangedNT = NOTIFICATION_TYPE_CHANGED;
+ registerNotificationRspAddressedPlayerChangedNative(
+ deviceFeatures[i].mAddressedPlayerChangedNT,
+ playerId, getByteAddress(deviceFeatures[i].mCurrentDevice));
+ if (previousAddressedPlayerId != INVALID_ADDRESSED_PLAYER_ID) {
+ resetAndSendPlayerStatusReject();
+ }
+ } else {
+ if (DEBUG)
+ Log.v(TAG, "Do not reset notifications, ADDR_PLAYR_CHNGD not registered");
}
- } else {
- if (DEBUG) Log.v(TAG, "Do not reset notifications, ADDR_PLAYR_CHNGD not registered");
- mAddressedPlayerId = playerId;
}
+ mAddressedPlayerId = playerId;
}
- private void resetAndSendPlayerStatusReject() {
- if (DEBUG) Log.v(TAG, "resetAndSendPlayerStatusReject");
+ public void updateResetNotification(int notificationType) {
+ Log.v(TAG,"notificationType " + notificationType);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ switch (notificationType) {
+ case PLAY_STATUS_CHANGE_NOTIFICATION:
+ if (deviceFeatures[i].mPlayStatusChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) {
+ deviceFeatures[i].mPlayStatusChangedNT =
+ NOTIFICATION_TYPE_REJECT;
+ registerNotificationRspPlayStatusNative(
+ deviceFeatures[i].mPlayStatusChangedNT,
+ PLAYSTATUS_STOPPED,
+ getByteAddress(deviceFeatures[i].mCurrentDevice));
+ } else {
+ Log.v(TAG,"i " + i + " status is"+
+ deviceFeatures[i].mPlayStatusChangedNT);
+ }
+ break;
+ case PLAY_POSITION_CHANGE_NOTIFICATION:
+ if (deviceFeatures[i].mPlayPosChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) {
+ if (DEBUG)
+ Log.v(TAG, "send Play Position reject to stack");
+ deviceFeatures[i].mPlayPosChangedNT =
+ NOTIFICATION_TYPE_REJECT;
+ registerNotificationRspPlayPosNative(
+ deviceFeatures[i].mPlayPosChangedNT,
+ -1 ,getByteAddress(deviceFeatures[i].mCurrentDevice));
+ mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
+ } else {
+ Log.v(TAG,"i " + i + " status is"+
+ deviceFeatures[i].mPlayPosChangedNT);
+ }
- if (mPlayStatusChangedNT == NOTIFICATION_TYPE_INTERIM) {
- if (DEBUG) Log.v(TAG, "send Play Status reject to stack");
- mPlayStatusChangedNT = NOTIFICATION_TYPE_REJECT;
- registerNotificationRspPlayStatusNative(mPlayStatusChangedNT, PLAYSTATUS_STOPPED);
- }
- if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) {
- if (DEBUG) Log.v(TAG, "send Play Position reject to stack");
- mPlayPosChangedNT = NOTIFICATION_TYPE_REJECT;
- registerNotificationRspPlayPosNative(mPlayPosChangedNT, -1);
- mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
- }
- if (mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) {
- if (DEBUG) Log.v(TAG, "send Track Changed reject to stack");
- mTrackChangedNT = NOTIFICATION_TYPE_REJECT;
- byte[] track = new byte[TRACK_ID_SIZE];
- /* track is stored in big endian format */
- for (int i = 0; i < TRACK_ID_SIZE; ++i) {
- track[i] = (byte) (mTrackNumber >> (56 - 8 * i));
+ break;
+ case TRACK_CHANGE_NOTIFICATION:
+ if (deviceFeatures[i].mTrackChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) {
+ if (DEBUG)
+ Log.v(TAG, "send Track Changed reject to stack");
+ deviceFeatures[i].mTrackChangedNT =
+ NOTIFICATION_TYPE_REJECT;
+ byte[] track = new byte[TRACK_ID_SIZE];
+ /* track is stored in big endian format */
+ for (int j = 0; j < TRACK_ID_SIZE; ++j) {
+ track[j] = (byte) (mTrackNumber >> (56 - 8 * j));
+ }
+ registerNotificationRspTrackChangeNative(
+ deviceFeatures[i].mTrackChangedNT ,
+ track ,getByteAddress(deviceFeatures[i].mCurrentDevice));
+ } else {
+ Log.v(TAG,"i " + i + " status is"+
+ deviceFeatures[i].mTrackChangedNT);
+ }
+
+ break;
+ case NOW_PALYING_CONTENT_CHANGED_NOTIFICATION:
+ if (deviceFeatures[i].mNowPlayingContentChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) {
+ if (DEBUG)
+ Log.v(TAG, "send Now playing changed reject to stack");
+ deviceFeatures[i].mNowPlayingContentChangedNT =
+ NOTIFICATION_TYPE_REJECT;
+ registerNotificationRspNowPlayingContentChangedNative(
+ deviceFeatures[i].mNowPlayingContentChangedNT ,
+ getByteAddress(deviceFeatures[i].mCurrentDevice));
+ } else {
+ Log.v(TAG,"i " + i + " status is"+
+ deviceFeatures[i].mNowPlayingContentChangedNT);
+ }
+
+ break;
+ default :
+ Log.e(TAG,"Invalid Notification type ");
}
- registerNotificationRspTrackChangeNative(mTrackChangedNT, track);
- }
- if (mNowPlayingContentChangedNT == NOTIFICATION_TYPE_INTERIM) {
- if (DEBUG) Log.v(TAG, "send Now playing changed reject to stack");
- mNowPlayingContentChangedNT = NOTIFICATION_TYPE_REJECT;
- registerNotificationRspNowPlayingContentChangedNative(mNowPlayingContentChangedNT);
}
}
+ private void resetAndSendPlayerStatusReject() {
+ if (DEBUG)
+ Log.v(TAG, "resetAndSendPlayerStatusReject");
+ updateResetNotification(PLAY_STATUS_CHANGE_NOTIFICATION);
+ updateResetNotification(PLAY_POSITION_CHANGE_NOTIFICATION);
+ updateResetNotification(TRACK_CHANGE_NOTIFICATION);
+ updateResetNotification(NOW_PALYING_CONTENT_CHANGED_NOTIFICATION);
+ }
+
void updateBrowsedPlayerFolder(int numOfItems, int folderDepth, String[] folderNames) {
Log.v(TAG, "updateBrowsedPlayerFolder: folderDepth: " + folderDepth);
- mCurrentPath = PATH_ROOT;
- mCurrentPathUid = null;
+ if (mBrowserDevice == null) {
+ Log.e(TAG,"mBrowserDevice is null for music player called api");
+ }
+ BluetoothDevice device = mBrowserDevice;
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ROOT;
+ deviceFeatures[deviceIndex].mCurrentPathUid = null;
+ deviceFeatures[deviceIndex].mMediaUri = mMediaUriStatic;
+ mMediaUriStatic = null;
if (folderDepth > 0) {
- setBrowsedPlayerRspNative((byte)OPERATION_SUCCESSFUL, 0x0, numOfItems,
- folderDepth, CHAR_SET_UTF8, folderNames);
+ setBrowsedPlayerRspNative((byte)OPERATION_SUCCESSFUL ,
+ 0x0, numOfItems, folderDepth, CHAR_SET_UTF8,
+ folderNames, getByteAddress(device));
} else {
- setBrowsedPlayerRspNative((byte)INTERNAL_ERROR, 0x0, numOfItems,
- folderDepth, CHAR_SET_UTF8, folderNames);
+ setBrowsedPlayerRspNative((byte)INTERNAL_ERROR ,
+ 0x0, numOfItems, folderDepth, CHAR_SET_UTF8,
+ folderNames, getByteAddress(device));
}
+ mBrowserDevice = null;
}
void updateNowPlayingContentChanged() {
Log.v(TAG, "updateNowPlayingContentChanged");
- if (mNowPlayingContentChangedNT == NOTIFICATION_TYPE_INTERIM) {
- Log.v(TAG, "Notify peer on updateNowPlayingContentChanged");
- mNowPlayingContentChangedNT = NOTIFICATION_TYPE_CHANGED;
- registerNotificationRspNowPlayingContentChangedNative(mNowPlayingContentChangedNT);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mNowPlayingContentChangedNT ==
+ NOTIFICATION_TYPE_INTERIM) {
+ Log.v(TAG, "Notify peer on updateNowPlayingContentChanged");
+ deviceFeatures[i].mNowPlayingContentChangedNT = NOTIFICATION_TYPE_CHANGED;
+ registerNotificationRspNowPlayingContentChangedNative(
+ deviceFeatures[i].mNowPlayingContentChangedNT ,
+ getByteAddress(deviceFeatures[i].mCurrentDevice));
+ }
}
}
void updatePlayItemResponse(boolean success) {
Log.v(TAG, "updatePlayItemResponse: success: " + success);
+ BluetoothDevice device = mBrowserDevice;
+ if (mBrowserDevice == null) {
+ Log.e(TAG, "mBrowserDevice is null for music app called API");
+ }
+ /* add member for getting current setting get play item pending rsp
+ * and clear it when this is recieved */
if (success) {
- playItemRspNative(OPERATION_SUCCESSFUL);
+ playItemRspNative(OPERATION_SUCCESSFUL ,
+ getByteAddress(device));
+
} else {
- playItemRspNative(INTERNAL_ERROR);
+ playItemRspNative(INTERNAL_ERROR ,
+ getByteAddress(device));
}
+ mBrowserDevice = null;
}
void updateNowPlayingEntriesReceived(long[] playList) {
+ Log.e(TAG,"updateNowPlayingEntriesReceived called");
int status = OPERATION_SUCCESSFUL;
int numItems = 0;
long reqItems = (mCachedRequest.mEnd - mCachedRequest.mStart) + 1;
@@ -1286,6 +1818,15 @@ public final class Avrcp {
String[] attValues = new String[MAX_BROWSE_ITEM_TO_SEND * 7];
int[] attIds = new int[MAX_BROWSE_ITEM_TO_SEND * 7];
int index;
+ if (mBrowserDevice == null) {
+ Log.e(TAG,"mBrowserDevice is null for music app called API");
+ }
+ BluetoothDevice device = mBrowserDevice;
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid device index");
+ return;
+ }
Log.v(TAG, "updateNowPlayingEntriesReceived");
@@ -1298,16 +1839,20 @@ public final class Avrcp {
availableItems = playList.length;
if ((mCachedRequest.mStart + 1) > availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
if ((mCachedRequest.mStart < 0) || (mCachedRequest.mEnd < 0) ||
(mCachedRequest.mStart > mCachedRequest.mEnd)) {
Log.i(TAG, "wrong start / end index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
@@ -1324,7 +1869,7 @@ public final class Avrcp {
for (index = 0; index < reqItems; index++) {
try {
cursor = mContext.getContentResolver().query(
- mMediaUri, mCursorCols,
+ deviceFeatures[deviceIndex].mMediaUri, mCursorCols,
MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id=" +
playList[index + (int)mCachedRequest.mStart], null, null);
if (cursor != null) {
@@ -1339,25 +1884,32 @@ public final class Avrcp {
for (int attIndex = 0; attIndex < mCachedRequest.mAttrCnt; attIndex++) {
int attr = mCachedRequest.mAttrList.get(attIndex).intValue();
if ((attr <= MEDIA_ATTR_MAX) && (attr >= MEDIA_ATTR_MIN)) {
- attValues[(7 * index) + attIndex] =
- getAttributeStringFromCursor(cursor, attr);
+ attValues[(7 * index) + attIndex] = getAttributeStringFromCursor(
+ cursor, attr, deviceIndex);
attIds[(7 * index) + attIndex] = attr;
validAttrib ++;
}
}
- cursor.close();
numAtt[index] = (byte)validAttrib;
}
} catch(Exception e) {
- Log.i(TAG, "Exception "+ e);
- cursor.close();
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ Log.i(TAG, "Exception e"+ e);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
numItems = index;
- getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL, numItems, itemType, uid,
- type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ mBrowserDevice = null;
}
class CachedRequest {
@@ -1382,14 +1934,16 @@ public final class Avrcp {
long mEnd;
int mAttrCnt;
int mNumAttr;
+ String mAddress;
ArrayList<Integer> mAttrList;
public FolderListEntries(byte scope, long start, long end, int attrCnt, int numAttr,
- int[] attrs) {
+ int[] attrs, String deviceAddress) {
mScope = scope;
mStart = start;
mEnd = end;
mAttrCnt = attrCnt;
mNumAttr = numAttr;
+ mAddress = deviceAddress;
int i;
mAttrList = new ArrayList<Integer>();
for (i = 0; i < numAttr; ++i) {
@@ -1419,89 +1973,65 @@ public final class Avrcp {
}
}
- private void updateTrackNumber() {
- if (DEBUG) Log.v(TAG, "updateTrackNumber");
- if (mMediaPlayers.size() > 0) {
- final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
- while (rccIterator.hasNext()) {
- final MediaPlayerInfo di = rccIterator.next();
- if (di.GetPlayerFocus()) {
- di.SetTrackNumber(mTrackNumber);
- break;
- }
- }
- }
- }
-
private void updateMetadata(MetadataEditor data) {
- if (DEBUG) Log.v(TAG, "updateMetadata");
- if (mMediaPlayers.size() > 0) {
- final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
- while (rccIterator.hasNext()) {
- final MediaPlayerInfo di = rccIterator.next();
- if (di.GetPlayerFocus()) {
- if (DEBUG) Log.v(TAG, "resetting current MetaData");
- mMetadata.artist = di.GetMetadata().artist;
- mMetadata.trackTitle = di.GetMetadata().trackTitle;
- mMetadata.albumTitle = di.GetMetadata().albumTitle;
- mMetadata.genre = di.GetMetadata().genre;
- mMetadata.tracknum = di.GetMetadata().tracknum;
- break;
- }
- }
- }
+ if (DEBUG)
+ Log.v(TAG, "updateMetadata");
String oldMetadata = mMetadata.toString();
mMetadata.artist = data.getString(MediaMetadataRetriever.METADATA_KEY_ARTIST, null);
mMetadata.trackTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_TITLE, null);
mMetadata.albumTitle = data.getString(MediaMetadataRetriever.METADATA_KEY_ALBUM, null);
mMetadata.genre = data.getString(MediaMetadataRetriever.METADATA_KEY_GENRE, null);
- mTrackNumber = data.getLong(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS, 0L);
+ //mTrackNumber = data.getLong(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS, -1L);
mMetadata.tracknum = data.getLong(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, 0L);
Log.v(TAG,"old Metadata = " + oldMetadata);
Log.v(TAG,"new MetaData " + mMetadata.toString());
- if (mMediaPlayers.size() > 0) {
- final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
- while (rccIterator.hasNext()) {
- final MediaPlayerInfo di = rccIterator.next();
- if (di.GetPlayerFocus()) {
- if (DEBUG) Log.v(TAG, "updating List MetaData");
- di.SetMetadata(mMetadata);
- break;
- }
- }
- }
-
if (!oldMetadata.equals(mMetadata.toString())) {
- updateTrackNumber();
Log.v(TAG,"new mMetadata, mTrackNumber update to " + mTrackNumber);
-
- if (mTrackChangedNT == NOTIFICATION_TYPE_INTERIM) {
- mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
- sendTrackChangedRsp();
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if ((deviceFeatures[i].mCurrentDevice != null) &&
+ (deviceFeatures[i].mTrackChangedNT == NOTIFICATION_TYPE_INTERIM)) {
+ deviceFeatures[i].mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
+ Log.v(TAG,"sending track change for device " + i);
+ sendTrackChangedRsp(deviceFeatures[i].mCurrentDevice);
+ }
}
-
if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
mCurrentPosMs = 0L;
- if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
- mPlayStartTimeMs = SystemClock.elapsedRealtime();
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if ((deviceFeatures[i].mCurrentDevice != null) &&
+ (deviceFeatures[i].mCurrentPlayState ==
+ RemoteControlClient.PLAYSTATE_PLAYING)) {
+ Log.i(TAG,"updated mPlayStartTimeMs");
+ mPlayStartTimeMs = SystemClock.elapsedRealtime();
+ break;
+ }
}
}
/* need send play position changed notification when track is changed */
- if (mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM) {
- mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
- registerNotificationRspPlayPosNative(mPlayPosChangedNT,
- (int)getPlayPosition());
- mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ Log.v(TAG,i + " mCurrentPlayState " + deviceFeatures[i].mCurrentPlayState);
+ if (deviceFeatures[i].mPlayPosChangedNT == NOTIFICATION_TYPE_INTERIM &&
+ deviceFeatures[i].mCurrentPlayState ==
+ RemoteControlClient.PLAYSTATE_PLAYING) {
+ Log.v(TAG,"sending play pos change for device " + i);
+ deviceFeatures[i].mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
+ registerNotificationRspPlayPosNative(deviceFeatures[i].mPlayPosChangedNT,
+ (int)getPlayPosition(deviceFeatures[i].mCurrentDevice) ,
+ getByteAddress(deviceFeatures[i].mCurrentDevice));
+ mHandler.removeMessages(MESSAGE_PLAY_INTERVAL_TIMEOUT);
+ }
}
}
- if (DEBUG) Log.v(TAG, "mMetadata=" + mMetadata.toString());
+ if (DEBUG)
+ Log.v(TAG, "mMetadata=" + mMetadata.toString());
mSongLengthMs = data.getLong(MediaMetadataRetriever.METADATA_KEY_DURATION,
RemoteControlClient.PLAYBACK_POSITION_INVALID);
- if (DEBUG) Log.v(TAG, "duration=" + mSongLengthMs);
+ if (DEBUG)
+ Log.v(TAG, "duration=" + mSongLengthMs);
}
private void getRcFeatures(byte[] address, int features) {
@@ -1510,49 +2040,65 @@ public final class Avrcp {
mHandler.sendMessage(msg);
}
- private void getPlayStatus() {
- Message msg = mHandler.obtainMessage(MESSAGE_GET_PLAY_STATUS);
+ private void getPlayStatus(byte[] address) {
+ Message msg = mHandler.obtainMessage(MESSAGE_GET_PLAY_STATUS, 0, 0,
+ Utils.getAddressStringFromByte(address));
mHandler.sendMessage(msg);
}
- private void getElementAttr(byte numAttr, int[] attrs) {
+ private void getElementAttr(byte numAttr, int[] attrs, byte[] address) {
int i;
ArrayList<Integer> attrList = new ArrayList<Integer>();
for (i = 0; i < numAttr; ++i) {
attrList.add(attrs[i]);
}
- Message msg = mHandler.obtainMessage(MESSAGE_GET_ELEM_ATTRS, (int)numAttr, 0, attrList);
+ ItemAttr itemAttr = new ItemAttr(attrList, 0,
+ Utils.getAddressStringFromByte(address));
+ Message msg = mHandler.obtainMessage(MESSAGE_GET_ELEM_ATTRS, (int)numAttr, 0,
+ itemAttr);
mHandler.sendMessage(msg);
}
- private void setBrowsedPlayer(int playerId) {
- if (DEBUG) Log.v(TAG, "setBrowsedPlayer: PlayerID: " + playerId);
- Message msg = mHandler.obtainMessage(MESSAGE_SET_BROWSED_PLAYER, playerId, 0, 0);
+ private void setBrowsedPlayer(int playerId, byte[] address) {
+ if (DEBUG)
+ Log.v(TAG, "setBrowsedPlayer: PlayerID: " + playerId);
+ Message msg = mHandler.obtainMessage(MESSAGE_SET_BROWSED_PLAYER, playerId, 0,
+ Utils.getAddressStringFromByte(address));
mHandler.sendMessage(msg);
}
- private void processSetBrowsedPlayer(int playerId) {
+ private void processSetBrowsedPlayer(int playerId, String deviceAddress) {
String packageName = null;
- byte retError = PLAYER_NOT_BROWSABLE;
- /*Following gets updated if SetBrowsed Player succeeds*/
- mCurrentPath = PATH_INVALID;
- mMediaUri = Uri.EMPTY;
- mCurrentPathUid = null;
- if (DEBUG) Log.v(TAG, "processSetBrowsedPlayer: PlayerID: " + playerId);
+ byte retError = INVALID_PLAYER_ID;
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.v(TAG,"device entry not present, bailing out");
+ return;
+ }
+ /* Following gets updated if SetBrowsed Player succeeds */
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_INVALID;
+ deviceFeatures[deviceIndex].mMediaUri = Uri.EMPTY;
+ deviceFeatures[deviceIndex].mCurrentPathUid = null;
+ if (DEBUG)
+ Log.v(TAG, "processSetBrowsedPlayer: PlayerID: " + playerId);
if (mMediaPlayers.size() > 0) {
final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
while (rccIterator.hasNext()) {
final MediaPlayerInfo di = rccIterator.next();
if (di.RetrievePlayerId() == playerId) {
if (di.GetPlayerAvailablility()) {
- if (DEBUG) Log.v(TAG, "player found and available");
+ if (DEBUG)
+ Log.v(TAG, "player found and available");
if (di.IsPlayerBrowsable()) {
if (di.IsPlayerBrowsableWhenAddressed()) {
if (di.GetPlayerFocus()) {
packageName = di.RetrievePlayerPackageName();
- if (DEBUG) Log.v(TAG, "player addressed hence browsable");
+ if (DEBUG)
+ Log.v(TAG, "player addressed hence browsable");
} else {
- if (DEBUG) Log.v(TAG, "Reject: player browsable only" +
+ if (DEBUG)
+ Log.v(TAG, "Reject: player browsable only" +
"when addressed");
retError = PLAYER_NOT_ADDRESSED;
}
@@ -1566,53 +2112,94 @@ public final class Avrcp {
}
if (packageName != null) {
mRemoteController.setRemoteControlClientBrowsedPlayer();
+ mBrowserDevice = device;
} else {
- if (DEBUG) Log.v(TAG, "player not available for browse");
- setBrowsedPlayerRspNative(retError, 0x0, 0, 0, 0, null);
+ if (DEBUG)
+ Log.v(TAG, "player not available for browse");
+ setBrowsedPlayerRspNative(retError ,
+ 0x0, 0x0, 0x0, 0x0,
+ null, getByteAddress(device));
}
}
- private void fastForward(int keyState) {
- Message msg = mHandler.obtainMessage(MESSAGE_FAST_FORWARD, keyState, 0);
- mHandler.sendMessage(msg);
+ private void fastForward(int keyState, String deviceAddress) {
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+ if ((keyState == deviceFeatures[deviceIndex].keyPressState) &&
+ (keyState == KEY_STATE_RELEASE)) {
+ Log.e(TAG, "Ignore key release event");
+ } else {
+ Message msg = mHandler.obtainMessage(MESSAGE_FAST_FORWARD, keyState,
+ 0, deviceAddress);
+ mHandler.sendMessage(msg);
+ deviceFeatures[deviceIndex].keyPressState = keyState;
+ }
}
- private void rewind(int keyState) {
- Message msg = mHandler.obtainMessage(MESSAGE_REWIND, keyState, 0);
- mHandler.sendMessage(msg);
+ private void rewind(int keyState, String deviceAddress) {
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+ if ((keyState == deviceFeatures[deviceIndex].keyPressState) &&
+ (keyState == KEY_STATE_RELEASE)) {
+ Log.e(TAG, "Ignore key release event");
+ } else {
+ Message msg = mHandler.obtainMessage(MESSAGE_REWIND, keyState, 0,
+ deviceAddress);
+ mHandler.sendMessage(msg);
+ deviceFeatures[deviceIndex].keyPressState = keyState;
+ }
}
- private void changePath(byte direction, long uid) {
- if (DEBUG) Log.v(TAG, "changePath: direction: " + direction + " uid:" + uid);
- Message msg = mHandler.obtainMessage(MESSAGE_CHANGE_PATH, direction, 0, uid);
+ private void changePath(byte direction, long uid, byte[] address) {
+ if (DEBUG)
+ Log.v(TAG, "changePath: direction: " + direction + " uid:" + uid);
+ ItemAttr itemAttr = new ItemAttr(null, uid,
+ Utils.getAddressStringFromByte(address));
+ Message msg = mHandler.obtainMessage(MESSAGE_CHANGE_PATH, direction, 0, itemAttr);
mHandler.sendMessage(msg);
}
- private void processChangePath(int direction, long folderUid) {
- if (DEBUG) Log.v(TAG, "processChangePath: direction: " + direction +
- " uid:" + folderUid);
+ private void processChangePath(int direction, long folderUid,
+ String deviceAddress) {
+ if (DEBUG)
+ Log.v(TAG, "processChangePath: direction: " + direction +
+ " uid:" + folderUid);
long numberOfItems = 0;
int status = OPERATION_SUCCESSFUL;
- if (mCurrentPath.equals(PATH_ROOT)){
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.v(TAG,"device entry not present, bailing out");
+ return;
+ }
+ if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ROOT)){
switch (direction) {
case FOLDER_UP:
status = DOES_NOT_EXIST;
break;
case FOLDER_DOWN:
if (folderUid == UID_TITLES) {
- mCurrentPath = PATH_TITLES;
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_TITLES;
numberOfItems = getNumItems(PATH_TITLES,
- MediaStore.Audio.Media.TITLE);
+ MediaStore.Audio.Media.TITLE, deviceIndex);
} else if (folderUid == UID_ALBUM) {
- mCurrentPath = PATH_ALBUMS;
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ALBUMS;
numberOfItems = getNumItems(PATH_ALBUMS,
- MediaStore.Audio.Media.ALBUM_ID);
+ MediaStore.Audio.Media.ALBUM_ID, deviceIndex);
} else if (folderUid == UID_ARTIST) {
- mCurrentPath = PATH_ARTISTS;
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ARTISTS;
numberOfItems = getNumItems(PATH_ARTISTS,
- MediaStore.Audio.Media.ARTIST_ID);
+ MediaStore.Audio.Media.ARTIST_ID, deviceIndex);
} else if (folderUid == UID_PLAYLIST) {
- mCurrentPath = PATH_PLAYLISTS;
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_PLAYLISTS;
numberOfItems = getNumPlaylistItems();
} else {
status = DOES_NOT_EXIST;
@@ -1622,17 +2209,17 @@ public final class Avrcp {
status = INVALID_DIRECTION;
break;
}
- } else if (mCurrentPath.equals(PATH_TITLES)) {
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_TITLES)) {
switch (direction) {
case FOLDER_UP:
- mCurrentPath = PATH_ROOT;
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ROOT;
numberOfItems = NUM_ROOT_ELEMENTS;
break;
case FOLDER_DOWN:
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {MediaStore.Audio.Media.TITLE},
MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id="
+ folderUid, null, null);
@@ -1640,36 +2227,40 @@ public final class Avrcp {
status = NOT_A_DIRECTORY;
else
status = DOES_NOT_EXIST;
- cursor.close();
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- changePathRspNative(INTERNAL_ERROR, numberOfItems);
+ changePathRspNative(INTERNAL_ERROR ,
+ numberOfItems ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
break;
default:
status = INVALID_DIRECTION;
break;
}
- } else if (mCurrentPath.equals(PATH_ALBUMS)) {
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ALBUMS)) {
switch (direction) {
case FOLDER_UP:
- if (mCurrentPathUid == null) { // Path @ Album
- mCurrentPath = PATH_ROOT;
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) { // Path @ Album
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ROOT;
numberOfItems = NUM_ROOT_ELEMENTS;
} else { // Path @ individual album id
- mCurrentPath = PATH_ALBUMS;
- mCurrentPathUid = null;
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ALBUMS;
+ deviceFeatures[deviceIndex].mCurrentPathUid = null;
numberOfItems = getNumItems(PATH_ALBUMS,
- MediaStore.Audio.Media.ALBUM_ID);
+ MediaStore.Audio.Media.ALBUM_ID, deviceIndex);
}
break;
case FOLDER_DOWN:
- if (mCurrentPathUid == null) { // Path @ Album
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) { // Path @ Album
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {MediaStore.Audio.Media.ALBUM},
MediaStore.Audio.Media.IS_MUSIC + "=1 AND " +
MediaStore.Audio.Media.ALBUM_ID + "=" + folderUid,
@@ -1678,33 +2269,43 @@ public final class Avrcp {
status = DOES_NOT_EXIST;
} else{
numberOfItems = cursor.getCount();
- mCurrentPathUid = String.valueOf(folderUid);
- cursor.close();
+ deviceFeatures[deviceIndex].mCurrentPathUid =
+ String.valueOf(folderUid);
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- changePathRspNative(INTERNAL_ERROR, numberOfItems);
+ changePathRspNative(INTERNAL_ERROR ,
+ numberOfItems ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
} else { // Path @ Individual Album id
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {MediaStore.Audio.Media.TITLE},
MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id=" + folderUid,
null, null);
- // As Individual Album path can not have any folder in it hence return
- // the error as applicable, depending on whether uid passed exists.
+ /* As Individual Album path can not have any folder in it hence return
+ * the error as applicable, depending on whether uid passed
+ * exists. */
if (cursor != null)
status = NOT_A_DIRECTORY;
else
status = DOES_NOT_EXIST;
- cursor.close();
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- changePathRspNative(INTERNAL_ERROR, numberOfItems);
+ changePathRspNative(INTERNAL_ERROR ,
+ numberOfItems ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
break;
@@ -1712,25 +2313,25 @@ public final class Avrcp {
status = INVALID_DIRECTION;
break;
}
- } else if (mCurrentPath.equals(PATH_ARTISTS)) {
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ARTISTS)) {
switch(direction) {
case FOLDER_UP:
- if (mCurrentPathUid == null) {
- mCurrentPath = PATH_ROOT;
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ROOT;
numberOfItems = NUM_ROOT_ELEMENTS;
} else {
- mCurrentPath = PATH_ARTISTS;
- mCurrentPathUid = null;
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ARTISTS;
+ deviceFeatures[deviceIndex].mCurrentPathUid = null;
numberOfItems = getNumItems(PATH_ARTISTS,
- MediaStore.Audio.Media.ARTIST_ID);
+ MediaStore.Audio.Media.ARTIST_ID, deviceIndex);
}
break;
case FOLDER_DOWN:
- if (mCurrentPathUid == null) {
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {MediaStore.Audio.Media.ARTIST},
MediaStore.Audio.Media.IS_MUSIC + "=1 AND " +
MediaStore.Audio.Media.ARTIST_ID + "=" + folderUid,
@@ -1739,20 +2340,25 @@ public final class Avrcp {
status = DOES_NOT_EXIST;
} else{
numberOfItems = cursor.getCount();
- mCurrentPathUid = String.valueOf(folderUid);
- mCurrentPath = PATH_ARTISTS;
- cursor.close();
+ deviceFeatures[deviceIndex].mCurrentPathUid =
+ String.valueOf(folderUid);
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ARTISTS;
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- changePathRspNative(INTERNAL_ERROR, numberOfItems);
+ changePathRspNative(INTERNAL_ERROR ,
+ numberOfItems ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
} else {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {MediaStore.Audio.Media.TITLE},
MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id="
+ folderUid, null, null);
@@ -1760,11 +2366,15 @@ public final class Avrcp {
status = NOT_A_DIRECTORY;
else
status = DOES_NOT_EXIST;
- cursor.close();
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- changePathRspNative(INTERNAL_ERROR, numberOfItems);
+ changePathRspNative(INTERNAL_ERROR ,
+ numberOfItems ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
break;
@@ -1772,20 +2382,20 @@ public final class Avrcp {
status = INVALID_DIRECTION;
break;
}
- } else if (mCurrentPath.equals(PATH_PLAYLISTS)) {
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_PLAYLISTS)) {
switch(direction) {
case FOLDER_UP:
- if (mCurrentPathUid == null) {
- mCurrentPath = PATH_ROOT;
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_ROOT;
numberOfItems = NUM_ROOT_ELEMENTS;
} else {
- mCurrentPath = PATH_PLAYLISTS;
- mCurrentPathUid = null;
+ deviceFeatures[deviceIndex].mCurrentPath = PATH_PLAYLISTS;
+ deviceFeatures[deviceIndex].mCurrentPathUid = null;
numberOfItems = getNumPlaylistItems();
}
break;
case FOLDER_DOWN:
- if (mCurrentPathUid == null) {
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
Cursor cursor = null;
try {
String[] cols = new String[] {
@@ -1805,14 +2415,20 @@ public final class Avrcp {
status = DOES_NOT_EXIST;
} else{
numberOfItems = cursor.getCount();
- mCurrentPathUid = String.valueOf(folderUid);
- mCurrentPath = PATH_PLAYLISTS;
- cursor.close();
+ deviceFeatures[deviceIndex].mCurrentPathUid =
+ String.valueOf(folderUid);
+ deviceFeatures[deviceIndex].mCurrentPath =
+ PATH_PLAYLISTS;
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- changePathRspNative(INTERNAL_ERROR, numberOfItems);
+ changePathRspNative(INTERNAL_ERROR ,
+ numberOfItems ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
} else {
numberOfItems = 0;
@@ -1828,7 +2444,9 @@ public final class Avrcp {
status = DOES_NOT_EXIST;
}
Log.i(TAG, "Number of items " + numberOfItems + ", status: " + status);
- changePathRspNative(status, numberOfItems);
+ changePathRspNative(status ,
+ numberOfItems ,
+ getByteAddress(device));
}
private long getNumPlaylistItems() {
@@ -1847,23 +2465,25 @@ public final class Avrcp {
return 0;
} else {
long count = cursor.getCount();
- cursor.close();
return count;
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
return 0;
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
- private long getNumItems(String path, String element) {
+ private long getNumItems(String path, String element, int deviceIndex) {
if (path == null || element == null)
return 0;
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {element},
MediaStore.Audio.Media.IS_MUSIC + "=1", null,
element);
@@ -1871,7 +2491,6 @@ public final class Avrcp {
return 0;
} else if (path.equals(PATH_TITLES)) {
long count = cursor.getCount();
- cursor.close();
return count;
} else if (path.equals(PATH_ALBUMS) || path.equals(PATH_ARTISTS)){
long elemCount = 0;
@@ -1890,27 +2509,43 @@ public final class Avrcp {
count--;
}
Log.i(TAG, "element Count is "+ elemCount);
- cursor.close();
return elemCount;
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
return 0;
}
- private void playItem(byte scope, long uid) {
- if (DEBUG) Log.v(TAG, "playItem: scope: " + scope + " uid:" + uid);
- Message msg = mHandler.obtainMessage(MESSAGE_PLAY_ITEM, scope, 0, uid);
+ private void playItem(byte scope, long uid, byte[] address) {
+ if (DEBUG)
+ Log.v(TAG, "playItem: scope: " + scope + " uid:" + uid);
+ ItemAttr itemAttr = new ItemAttr(null, uid,
+ Utils.getAddressStringFromByte(address));
+ Message msg = mHandler.obtainMessage(MESSAGE_PLAY_ITEM, scope, 0, itemAttr);
mHandler.sendMessage(msg);
}
- private void processPlayItem(int scope, long uid) {
- if (DEBUG) Log.v(TAG, "processPlayItem: scope: " + scope + " uid:" + uid);
+ private void processPlayItem(int scope, long uid,
+ String deviceAddress) {
+ if (DEBUG)
+ Log.v(TAG, "processPlayItem: scope: " + scope + " uid:" + uid);
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ mBrowserDevice = device;
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.v(TAG,"device entry not present, bailing out");
+ return;
+ }
if (uid < 0) {
- Log.e(TAG, "invalid uid");
- playItemRspNative(DOES_NOT_EXIST);
+ if (DEBUG)
+ Log.v(TAG, "invalid uid");
+ playItemRspNative(DOES_NOT_EXIST ,
+ getByteAddress(device));
return;
}
if (mMediaPlayers.size() > 0) {
@@ -1919,92 +2554,113 @@ public final class Avrcp {
final MediaPlayerInfo di = rccIterator.next();
if (di.GetPlayerFocus()) {
if (!di.IsRemoteAddressable()) {
- playItemRspNative(INTERNAL_ERROR);
- Log.e(TAG, "Play Item fails: Player not remote addressable");
+ playItemRspNative(INTERNAL_ERROR ,
+ getByteAddress(device));
+ if (DEBUG)
+ Log.v(TAG, "Play Item fails: Player not remote" +
+ "addressable");
return;
}
}
}
}
if (scope == SCOPE_VIRTUAL_FILE_SYS) {
- if (mCurrentPath.equals(PATH_ROOT)) {
- playItemRspNative(UID_A_DIRECTORY);
- } else if (mCurrentPath.equals(PATH_TITLES)) {
+ if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ROOT)) {
+ playItemRspNative(UID_A_DIRECTORY ,
+ getByteAddress(device));
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_TITLES)) {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {MediaStore.Audio.Media.TITLE},
MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id=" + uid,
null, null);
if ((cursor == null) || (cursor.getCount() == 0)) {
- Log.e(TAG, "No such track");
- playItemRspNative(DOES_NOT_EXIST);
+ Log.i(TAG, "No such track");
+ playItemRspNative(DOES_NOT_EXIST ,
+ getByteAddress(device));
} else {
Log.i(TAG, "Play uid:" + uid);
- cursor.close();
mRemoteController.setRemoteControlClientPlayItem(uid, scope);
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- playItemRspNative(INTERNAL_ERROR);
+ playItemRspNative(INTERNAL_ERROR ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
- } else if (mCurrentPath.equals(PATH_ALBUMS)) {
- if (mCurrentPathUid == null) {
- playItemRspNative(UID_A_DIRECTORY);
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ALBUMS)) {
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
+ playItemRspNative(UID_A_DIRECTORY ,
+ getByteAddress(device));
} else {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {MediaStore.Audio.Media.TITLE},
MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id=" + uid + " AND " +
- MediaStore.Audio.Media.ALBUM_ID + "=" + mCurrentPathUid,
+ MediaStore.Audio.Media.ALBUM_ID + "=" +
+ deviceFeatures[deviceIndex].mCurrentPathUid,
null, null);
if ((cursor == null) || (cursor.getCount() == 0)) {
Log.i(TAG, "No such track");
- playItemRspNative(DOES_NOT_EXIST);
+ playItemRspNative(DOES_NOT_EXIST ,
+ getByteAddress(device));
} else {
Log.i(TAG, "Play uid:" + uid);
- cursor.close();
mRemoteController.setRemoteControlClientPlayItem(uid, scope);
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- playItemRspNative(INTERNAL_ERROR);
+ playItemRspNative(INTERNAL_ERROR ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
- } else if (mCurrentPath.equals(PATH_ARTISTS)) {
- if (mCurrentPathUid == null) {
- playItemRspNative(UID_A_DIRECTORY);
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ARTISTS)) {
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
+ playItemRspNative(UID_A_DIRECTORY ,
+ getByteAddress(device));
} else {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
new String[] {MediaStore.Audio.Media.TITLE},
MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id=" + uid + " AND " +
- MediaStore.Audio.Media.ARTIST_ID + "=" + mCurrentPathUid,
+ MediaStore.Audio.Media.ARTIST_ID + "=" +
+ deviceFeatures[deviceIndex].mCurrentPathUid,
null, null);
if ((cursor == null) || (cursor.getCount() == 0)) {
Log.i(TAG, "No such track");
- playItemRspNative(DOES_NOT_EXIST);
+ playItemRspNative(DOES_NOT_EXIST ,
+ getByteAddress(device));
} else {
Log.i(TAG, "Play uid:" + uid);
- cursor.close();
mRemoteController.setRemoteControlClientPlayItem(uid, scope);
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- playItemRspNative(INTERNAL_ERROR);
+ playItemRspNative(INTERNAL_ERROR ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
- } else if (mCurrentPath.equals(PATH_PLAYLISTS)) {
- if (mCurrentPathUid == null) {
- playItemRspNative(UID_A_DIRECTORY);
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_PLAYLISTS)) {
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
+ playItemRspNative(UID_A_DIRECTORY ,
+ getByteAddress(device));
} else {
Cursor cursor = null;
try {
@@ -2020,7 +2676,7 @@ public final class Avrcp {
MediaStore.Audio.Media.IS_MUSIC
};
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external",
- Long.parseLong(mCurrentPathUid));
+ Long.parseLong(deviceFeatures[deviceIndex].mCurrentPathUid));
StringBuilder where = new StringBuilder();
where.append(MediaStore.Audio.Playlists.Members.AUDIO_ID + "=" + uid);
cursor = mContext.getContentResolver().query(uri, playlistMemberCols,
@@ -2029,39 +2685,49 @@ public final class Avrcp {
if ((cursor == null) || (cursor.getCount() == 0)) {
Log.i(TAG, "No such track");
- playItemRspNative(DOES_NOT_EXIST);
+ playItemRspNative(DOES_NOT_EXIST ,
+ getByteAddress(device));
} else {
Log.i(TAG, "Play uid:" + uid);
- cursor.close();
mRemoteController.setRemoteControlClientPlayItem(uid, scope);
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e);
- cursor.close();
- playItemRspNative(INTERNAL_ERROR);
+ playItemRspNative(INTERNAL_ERROR ,
+ getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
} else {
- playItemRspNative(DOES_NOT_EXIST);
+ playItemRspNative(DOES_NOT_EXIST ,
+ getByteAddress(device));
+
}
} else if (scope == SCOPE_NOW_PLAYING) {
mRemoteController.setRemoteControlClientPlayItem(uid, scope);
} else {
- playItemRspNative(DOES_NOT_EXIST);
- Log.e(TAG, "Play Item fails: Invalid scope");
+ playItemRspNative(DOES_NOT_EXIST ,
+ getByteAddress(device));
+ Log.v(TAG, "Play Item fails: Invalid scope");
}
}
- private void getItemAttr(byte scope, long uid, byte numAttr, int[] attrs) {
- if (DEBUG) Log.v(TAG, "getItemAttr: scope: " + scope + " uid:" + uid +
- " numAttr:" + numAttr);
+ private void getItemAttr(byte scope, long uid, byte numAttr, int[] attrs, byte[] address) {
+ if (DEBUG)
+ Log.v(TAG, "getItemAttr: scope: " + scope + " uid:" + uid +
+ " numAttr:" + numAttr);
int i;
ArrayList<Integer> attrList = new ArrayList<Integer>();
for (i = 0; i < numAttr; ++i) {
attrList.add(attrs[i]);
- if (DEBUG) Log.v(TAG, "attrs[" + i + "] = " + attrs[i]);
+ if (DEBUG)
+ Log.v(TAG, "attrs[" + i + "] = " + attrs[i]);
}
- ItemAttr itemAttr = new ItemAttr(attrList, uid);
+ ItemAttr itemAttr = new ItemAttr(attrList, uid,
+ Utils.getAddressStringFromByte(address));
Message msg = mHandler.obtainMessage(MESSAGE_GET_ITEM_ATTRS, (int)numAttr,
(int)scope, itemAttr);
mHandler.sendMessage(msg);
@@ -2081,68 +2747,105 @@ public final class Avrcp {
MediaStore.Audio.Media.BOOKMARK
};
- private void processGetItemAttr(byte scope, long uid, byte numAttr, int[] attrs) {
- if (DEBUG) Log.v(TAG, "processGetItemAttr: scope: " + scope + " uid:" + uid +
- " numAttr:" + numAttr);
+ private void processGetItemAttr(byte scope, long uid, byte numAttr, int[] attrs,
+ String deviceAddress) {
+ if (DEBUG)
+ Log.v(TAG, "processGetItemAttr: scope: " + scope + " uid:" + uid +
+ " numAttr:" + numAttr);
String[] textArray;
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.v(TAG,"device entry not present, bailing out");
+ return;
+ }
textArray = new String[numAttr];
if ((scope == SCOPE_VIRTUAL_FILE_SYS) || (scope == SCOPE_NOW_PLAYING)) {
Cursor cursor = null;
try {
- if ((mMediaUri == Uri.EMPTY) || (mCurrentPath.equals(PATH_INVALID))) {
- Log.e(TAG, "Browsed player not set, getItemAttr can not be processed");
- getItemAttrRspNative((byte)0, attrs, textArray);
+ if ((deviceFeatures[deviceIndex].mMediaUri == Uri.EMPTY) ||
+ (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_INVALID))) {
+ if (DEBUG)
+ Log.v(TAG, "Browsed player not set, getItemAttr can not be processed");
+ getItemAttrRspNative((byte)0 ,attrs ,
+ textArray ,getByteAddress(device));
return;
}
cursor = mContext.getContentResolver().query(
- mMediaUri, mCursorCols,
+ deviceFeatures[deviceIndex].mMediaUri, mCursorCols,
MediaStore.Audio.Media.IS_MUSIC + "=1 AND _id=" + uid, null, null);
if ((cursor == null) || (cursor.getCount() == 0)) {
Log.i(TAG, "Invalid track UID");
- getItemAttrRspNative((byte)0, attrs, textArray);
+ Log.i(TAG, "cursor is " + cursor);
+ if (cursor != null)
+ Log.i(TAG, "cursor.getCount() " + cursor.getCount());
+ getItemAttrRspNative((byte)0 ,attrs ,
+ textArray ,getByteAddress(device));
} else {
int validAttrib = 0;
cursor.moveToFirst();
for (int i = 0; i < numAttr; ++i) {
if ((attrs[i] <= MEDIA_ATTR_MAX) && (attrs[i] >= MEDIA_ATTR_MIN)) {
- textArray[i] = getAttributeStringFromCursor(cursor, attrs[i]);
+ textArray[i] = getAttributeStringFromCursor(
+ cursor, attrs[i], deviceIndex);
validAttrib ++;
}
}
- getItemAttrRspNative((byte)validAttrib, attrs, textArray);
- cursor.close();
+ getItemAttrRspNative(numAttr ,attrs ,
+ textArray ,getByteAddress(device));
}
} catch (Exception e) {
- Log.e(TAG, "Exception " + e); cursor.close();
- getItemAttrRspNative((byte)0, attrs, textArray);
+ Log.e(TAG, "Exception " + e);
+ getItemAttrRspNative((byte)0 ,attrs ,
+ textArray ,getByteAddress(device));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
} else {
Log.i(TAG, "Invalid scope");
- getItemAttrRspNative((byte)0, attrs, textArray);
+ getItemAttrRspNative((byte)0 ,attrs ,
+ textArray ,getByteAddress(device));
}
}
private class ItemAttr {
ArrayList<Integer> mAttrList;
long mUid;
- public ItemAttr (ArrayList<Integer> attrList, long uid) {
+ String mAddress;
+ public ItemAttr (ArrayList<Integer> attrList, long uid,
+ String deviceAddress) {
mAttrList = attrList;
mUid = uid;
+ mAddress = deviceAddress;
}
}
- private void setAddressedPlayer(int playerId) {
- if (DEBUG) Log.v(TAG, "setAddressedPlayer: PlayerID: " + playerId);
- Message msg = mHandler.obtainMessage(MESSAGE_SET_ADDR_PLAYER, playerId, 0, 0);
+ private void setAddressedPlayer(int playerId, byte[] address) {
+ if (DEBUG)
+ Log.v(TAG, "setAddressedPlayer: PlayerID: " + playerId);
+ Message msg = mHandler.obtainMessage(MESSAGE_SET_ADDR_PLAYER, playerId, 0,
+ Utils.getAddressStringFromByte(address));
mHandler.sendMessage(msg);
}
- private void processSetAddressedPlayer(int playerId) {
- if (DEBUG) Log.v(TAG, "processSetAddressedPlayer: PlayerID: " + playerId);
+ private void processSetAddressedPlayer(int playerId, String deviceAddress) {
+ if (DEBUG)
+ Log.v(TAG, "processSetAddressedPlayer: PlayerID: " + playerId);
String packageName = null;
- if (mRequestedAddressedPlayerPackageName != null) {
- if (DEBUG) Log.v(TAG, "setAddressedPlayer: Request in progress, Reject this Request");
- setAdressedPlayerRspNative ((byte)PLAYER_NOT_ADDRESSED);
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.v(TAG,"device entry not present, bailing out");
+ return;
+ }
+ if (deviceFeatures[deviceIndex].mRequestedAddressedPlayerPackageName !=
+ null) {
+ if (DEBUG)
+ Log.v(TAG, "setAddressedPlayer: Request in progress, Reject this Request");
+ setAdressedPlayerRspNative((byte)PLAYER_NOT_ADDRESSED,
+ getByteAddress(mAdapter.getRemoteDevice(deviceAddress)));
return;
}
if (mMediaPlayers.size() > 0) {
@@ -2156,62 +2859,82 @@ public final class Avrcp {
}
if(packageName != null) {
if (playerId == mAddressedPlayerId) {
- if (DEBUG) Log.v(TAG, "setAddressedPlayer: Already addressed, sending success");
- setAdressedPlayerRspNative ((byte)OPERATION_SUCCESSFUL);
+ if (DEBUG)
+ Log.v(TAG, "setAddressedPlayer: Already addressed, sending success");
+ setAdressedPlayerRspNative((byte)OPERATION_SUCCESSFUL,
+ getByteAddress(mAdapter.getRemoteDevice(deviceAddress)));
return;
}
String newPackageName = packageName.replace("com.android", "org.codeaurora");
Intent mediaIntent = new Intent(newPackageName + ".setaddressedplayer");
mediaIntent.setPackage(packageName);
- mContext.sendBroadcast(mediaIntent); // This needs to be caught in respective media players
- if (DEBUG) Log.v(TAG, "Intent Broadcasted: " + newPackageName + ".setaddressedplayer");
- mRequestedAddressedPlayerPackageName = packageName;
- Message msg = mHandler.obtainMessage(MESSAGE_SET_ADDR_PLAYER_REQ_TIMEOUT);
+ // This needs to be caught in respective media players
+ mContext.sendBroadcast(mediaIntent);
+ if (DEBUG)
+ Log.v(TAG, "Intent Broadcasted: " + newPackageName +
+ ".setaddressedplayer");
+ deviceFeatures[deviceIndex].mRequestedAddressedPlayerPackageName = packageName;
+ deviceFeatures[deviceIndex].isMusicAppResponsePending = true;
+ Message msg = mHandler.obtainMessage(MESSAGE_SET_ADDR_PLAYER_REQ_TIMEOUT,
+ 0, 0, deviceAddress);
mHandler.sendMessageDelayed(msg, AVRCP_BR_RSP_TIMEOUT);
Log.v(TAG, "Post MESSAGE_SET_ADDR_PLAYER_REQ_TIMEOUT");
} else {
- if (DEBUG) Log.v(TAG, "setAddressedPlayer fails: No such media player available");
- setAdressedPlayerRspNative ((byte)INVALID_PLAYER_ID);
+ if (DEBUG)
+ Log.v(TAG, "setAddressedPlayer fails: No such media player available");
+ setAdressedPlayerRspNative((byte)INVALID_PLAYER_ID,
+ getByteAddress(mAdapter.getRemoteDevice(deviceAddress)));
}
}
private void getFolderItems(byte scope, long start, long end, int attrCnt,
- int numAttr, int[] attrs) {
- if (DEBUG) Log.v(TAG, "getFolderItems");
- if (DEBUG) Log.v(TAG, "scope: " + scope + " attrCnt: " + attrCnt);
- if (DEBUG) Log.v(TAG, "start: " + start + " end: " + end);
+ int numAttr, int[] attrs, byte[] address) {
+ if (DEBUG)
+ Log.v(TAG, "getFolderItems");
+ if (DEBUG)
+ Log.v(TAG, "scope: " + scope + " attrCnt: " + attrCnt);
+ if (DEBUG)
+ Log.v(TAG, "start: " + start + " end: " + end);
for (int i = 0; i < numAttr; ++i) {
- if (DEBUG) Log.v(TAG, "attrs[" + i + "] = " + attrs[i]);
+ if (DEBUG)
+ Log.v(TAG, "attrs[" + i + "] = " + attrs[i]);
}
FolderListEntries folderListEntries = new FolderListEntries (scope, start, end, attrCnt,
- numAttr, attrs);
+ numAttr, attrs, Utils.getAddressStringFromByte(address));
Message msg = mHandler.obtainMessage(MESSAGE_GET_FOLDER_ITEMS, 0, 0, folderListEntries);
mHandler.sendMessage(msg);
}
private void processGetFolderItems(byte scope, long start, long end, int size,
- int numAttr, int[] attrs) {
- if (DEBUG) Log.v(TAG, "processGetFolderItems");
- if (DEBUG) Log.v(TAG, "scope: " + scope + " size: " + size);
- if (DEBUG) Log.v(TAG, "start: " + start + " end: " + end + " numAttr: " + numAttr);
+ int numAttr, int[] attrs, String deviceAddress) {
+ if (DEBUG)
+ Log.v(TAG, "processGetFolderItems");
+ if (DEBUG)
+ Log.v(TAG, "scope: " + scope + " size: " + size);
+ if (DEBUG)
+ Log.v(TAG, "start: " + start + " end: " + end + " numAttr: " + numAttr);
if (scope == SCOPE_PLAYER_LIST) { // populate mediaplayer item list here
- processGetMediaPlayerItems(scope, start, end, size, numAttr, attrs);
+ processGetMediaPlayerItems(scope, start, end, size, numAttr, attrs,
+ deviceAddress);
} else if ((scope == SCOPE_VIRTUAL_FILE_SYS) || (scope == SCOPE_NOW_PLAYING)) {
for (int i = 0; i < numAttr; ++i) {
- if (DEBUG) Log.v(TAG, "attrs[" + i + "] = " + attrs[i]);
+ if (DEBUG)
+ Log.v(TAG, "attrs[" + i + "] = " + attrs[i]);
}
- processGetFolderItemsInternal(scope, start, end, size, (byte)numAttr, attrs);
+ processGetFolderItemsInternal(scope, start, end, size, (byte)numAttr,
+ attrs, deviceAddress);
}
}
private void processGetMediaPlayerItems(byte scope, long start, long end, int size,
- int numAttr, int[] attrs) {
+ int numAttr, int[] attrs, String deviceAddress) {
byte[] folderItems = new byte[size];
int[] folderItemLengths = new int[32];
int availableMediaPlayers = 0;
int count = 0;
int positionItemStart = 0;
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
if (mMediaPlayers.size() > 0) {
final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
while (rccIterator.hasNext()) {
@@ -2231,23 +2954,27 @@ public final class Avrcp {
}
}
}
- if (DEBUG) Log.v(TAG, "Number of available MediaPlayers = " + availableMediaPlayers);
- getMediaPlayerListRspNative ((byte)OPERATION_SUCCESSFUL, 0x1357,
- availableMediaPlayers, folderItems, folderItemLengths);
+ if (DEBUG)
+ Log.v(TAG, "Number of available MediaPlayers = " +
+ availableMediaPlayers);
+ getMediaPlayerListRspNative((byte)OPERATION_SUCCESSFUL, 0x1357,
+ availableMediaPlayers, folderItems,
+ folderItemLengths, getByteAddress(device));
}
- private boolean isCurrentPathValid () {
- if (mCurrentPath.equals(PATH_ROOT) || mCurrentPath.equals(PATH_TITLES) ||
- mCurrentPath.equals(PATH_ALBUMS) || mCurrentPath.equals(PATH_ARTISTS) ||
- mCurrentPath.equals(PATH_PLAYLISTS)){
+ private boolean isCurrentPathValid (int deviceIndex) {
+ if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ROOT) ||
+ deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_TITLES) ||
+ deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ALBUMS) ||
+ deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ARTISTS) ||
+ deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_PLAYLISTS)) {
return true;
}
return false;
}
- private void processGetFolderItemsInternal(byte scope, long start, long end, long size,
- byte numAttr, int[] attrs) {
-
+ private void processGetFolderItemsInternal(byte scope, long start, long end, int size,
+ byte numAttr, int[] attrs, String deviceAddress) {
int status = OPERATION_SUCCESSFUL;
long numItems = 0;
long reqItems = (end - start) + 1;
@@ -2259,12 +2986,21 @@ public final class Avrcp {
byte[] numAtt = new byte[MAX_BROWSE_ITEM_TO_SEND];
String[] attValues = new String[MAX_BROWSE_ITEM_TO_SEND * 7];
int[] attIds = new int[MAX_BROWSE_ITEM_TO_SEND * 7];
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ mBrowserDevice = device;
- if (DEBUG) Log.v(TAG, "processGetFolderItemsInternal");
-
- if (DEBUG) Log.v(TAG, "requested attribute count" + numAttr);
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.v(TAG,"device entry not present, bailing out");
+ return;
+ }
+ if (DEBUG)
+ Log.v(TAG, "processGetFolderItemsInternal");
+ if (DEBUG)
+ Log.v(TAG, "requested attribute count" + numAttr);
for (int count = 0; count < numAttr; count++) {
- if (DEBUG) Log.v(TAG, "attr[" + count + "] = " + attrs[count]);
+ if (DEBUG)
+ Log.v(TAG, "attr[" + count + "] = " + attrs[count]);
}
if (scope == SCOPE_VIRTUAL_FILE_SYS) {
@@ -2274,38 +3010,51 @@ public final class Avrcp {
attIds[count] = 0;
}
- if (DEBUG) Log.v(TAG, "mCurrentPath: " + mCurrentPath);
- if (DEBUG) Log.v(TAG, "mCurrentPathUID: " + mCurrentPathUid);
- if (!isCurrentPathValid()) {
- getFolderItemsRspNative((byte)DOES_NOT_EXIST, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
- Log.e(TAG, "Current path not set");
+ if (DEBUG)
+ Log.v(TAG, "mCurrentPath: " +
+ deviceFeatures[deviceIndex].mCurrentPath);
+ if (DEBUG)
+ Log.v(TAG, "mCurrentPathUID: " +
+ deviceFeatures[deviceIndex].mCurrentPathUid);
+ if (!isCurrentPathValid(deviceIndex)) {
+ getFolderItemsRspNative((byte)DOES_NOT_EXIST ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ Log.v(TAG, "Current path not set");
return;
}
if ((start < 0) || (end < 0) || (start > end)) {
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
Log.e(TAG, "Wrong start/end index");
return;
}
- if (mCurrentPath.equals(PATH_ROOT)) {
+ if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ROOT)) {
long availableItems = NUM_ROOT_ELEMENTS;
if (start >= availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems, itemType, uid,
- type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
- if (DEBUG) Log.v(TAG, "availableItems: " + availableItems);
- if (DEBUG) Log.v(TAG, "reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "availableItems: " + availableItems);
+ if (DEBUG)
+ Log.v(TAG, "reqItems: " + reqItems);
availableItems = availableItems - start;
if (availableItems > MAX_BROWSE_ITEM_TO_SEND)
availableItems = MAX_BROWSE_ITEM_TO_SEND;
if (reqItems > availableItems)
reqItems = availableItems;
- if (DEBUG) Log.v(TAG, "revised reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "revised reqItems: " + reqItems);
numItems = reqItems;
@@ -2346,33 +3095,36 @@ public final class Avrcp {
break;
default:
Log.i(TAG, "wrong index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems,
- itemType, uid, type, playable, displayName, numAtt, attValues,
- attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
}
}
for (int count = 0; count < numItems; count++) {
Log.v(TAG, itemType[count] + "," + uid[count] + "," + type[count]);
}
- getFolderItemsRspNative((byte)status, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
- } else if (mCurrentPath.equals(PATH_TITLES)) {
+ getFolderItemsRspNative((byte)status ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_TITLES)) {
long availableItems = 0;
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
mCursorCols, MediaStore.Audio.Media.IS_MUSIC + "=1", null,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
if (cursor != null) {
availableItems = cursor.getCount();
if (start >= availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems,
- itemType, uid, type, playable, displayName, numAtt, attValues,
- attIds);
- cursor.close();
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
cursor.moveToFirst();
@@ -2381,19 +3133,23 @@ public final class Avrcp {
}
} else {
Log.i(TAG, "Error: could not fetch the elements");
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
- if (DEBUG) Log.v(TAG, "availableItems: " + availableItems);
- if (DEBUG) Log.v(TAG, "reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "availableItems: " + availableItems);
+ if (DEBUG)
+ Log.v(TAG, "reqItems: " + reqItems);
availableItems = availableItems - start;
if (availableItems > MAX_BROWSE_ITEM_TO_SEND)
availableItems = MAX_BROWSE_ITEM_TO_SEND;
if (reqItems > availableItems)
reqItems = availableItems;
- if (DEBUG) Log.v(TAG, "revised reqItems: " + reqItems);
-
+ if (DEBUG)
+ Log.v(TAG, "revised reqItems: " + reqItems);
int attIndex;
int index;
for (index = 0; index < reqItems; index++) {
@@ -2409,7 +3165,8 @@ public final class Avrcp {
if ((attrs[attIndex] <= MEDIA_ATTR_MAX) &&
(attrs[attIndex] >= MEDIA_ATTR_MIN)) {
attValues[(7 * index) + attIndex] =
- getAttributeStringFromCursor(cursor, attrs[attIndex]);
+ getAttributeStringFromCursor(
+ cursor, attrs[attIndex], deviceIndex);
attIds[(7 * index) + attIndex] = attrs[attIndex];
validAttrib ++;
}
@@ -2418,29 +3175,40 @@ public final class Avrcp {
cursor.moveToNext();
}
numItems = index;
- getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL, numItems, itemType, uid,
- type, playable, displayName, numAtt, attValues, attIds);
- cursor.close();
+ getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
} catch(Exception e) {
Log.i(TAG, "Exception e" + e);
- cursor.close();
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
- } else if (mCurrentPath.equals(PATH_ALBUMS)) {
- if (mCurrentPathUid == null) {
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ALBUMS)) {
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
long availableItems = 0;
Cursor cursor = null;
try {
- availableItems = getNumItems(PATH_ALBUMS, MediaStore.Audio.Media.ALBUM_ID);
+ availableItems = getNumItems(PATH_ALBUMS,
+ MediaStore.Audio.Media.ALBUM_ID, deviceIndex);
if (start >= availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
- if (DEBUG) Log.v(TAG, "availableItems: " + availableItems);
- if (DEBUG) Log.v(TAG, "reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "availableItems: " + availableItems);
+ if (DEBUG)
+ Log.v(TAG, "reqItems: " + reqItems);
availableItems = availableItems - start;
if (availableItems > MAX_BROWSE_ITEM_TO_SEND)
@@ -2450,7 +3218,7 @@ public final class Avrcp {
Log.i(TAG, "revised reqItems: " + reqItems);
cursor = mContext.getContentResolver().query(
- mMediaUri, mCursorCols,
+ deviceFeatures[deviceIndex].mMediaUri, mCursorCols,
MediaStore.Audio.Media.IS_MUSIC + "=1", null,
MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);
@@ -2459,8 +3227,10 @@ public final class Avrcp {
count = cursor.getCount();
} else {
Log.i(TAG, "Error: could not fetch the elements");
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
if (count < reqItems) {
@@ -2496,28 +3266,34 @@ public final class Avrcp {
}
if (index > 0) {
numItems = index;
- getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL, numItems,
- itemType, uid, type, playable, displayName, numAtt, attValues,
- attIds);
+ getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
} else {
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems,
- itemType, uid, type, playable, displayName, numAtt, attValues,
- attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
}
- cursor.close();
} catch(Exception e) {
Log.i(TAG, "Exception e" + e);
- cursor.close();
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
} else {
- long folderUid = Long.valueOf(mCurrentPathUid);
+ long folderUid = Long.valueOf(deviceFeatures[deviceIndex].mCurrentPathUid);
long availableItems = 0;
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
mCursorCols, MediaStore.Audio.Media.IS_MUSIC + "=1 AND " +
MediaStore.Audio.Media.ALBUM_ID + "=" + folderUid, null,
MediaStore.Audio.Albums.DEFAULT_SORT_ORDER);
@@ -2526,10 +3302,10 @@ public final class Avrcp {
availableItems = cursor.getCount();
if (start >= availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems,
- itemType, uid, type, playable, displayName, numAtt,
- attValues, attIds);
- cursor.close();
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
cursor.moveToFirst();
@@ -2538,20 +3314,24 @@ public final class Avrcp {
}
} else {
Log.i(TAG, "Error: could not fetch the elements");
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems,
- itemType, uid, type, playable, displayName, numAtt,
- attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
- if (DEBUG) Log.v(TAG, "availableItems: " + availableItems);
- if (DEBUG) Log.v(TAG, "reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "availableItems: " + availableItems);
+ if (DEBUG)
+ Log.v(TAG, "reqItems: " + reqItems);
availableItems = availableItems - start;
if (availableItems > MAX_BROWSE_ITEM_TO_SEND)
availableItems = MAX_BROWSE_ITEM_TO_SEND;
if (reqItems > availableItems)
reqItems = availableItems;
- if (DEBUG) Log.v(TAG, "revised reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "revised reqItems: " + reqItems);
int attIndex;
int index;
@@ -2568,7 +3348,8 @@ public final class Avrcp {
if ((attrs[attIndex] <= MEDIA_ATTR_MAX) &&
(attrs[attIndex] >= MEDIA_ATTR_MIN)) {
attValues[(7 * index) + attIndex] =
- getAttributeStringFromCursor(cursor, attrs[attIndex]);
+ getAttributeStringFromCursor(
+ cursor, attrs[attIndex], deviceIndex);
attIds[(7 * index) + attIndex] = attrs[attIndex];
validAttrib ++;
}
@@ -2577,41 +3358,52 @@ public final class Avrcp {
cursor.moveToNext();
}
numItems = index;
- getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL, numItems, itemType, uid,
- type, playable, displayName, numAtt, attValues, attIds);
- cursor.close();
+ getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
} catch(Exception e) {
Log.i(TAG, "Exception e" + e);
- cursor.close();
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
- } else if (mCurrentPath.equals(PATH_ARTISTS)) {
- if (mCurrentPathUid == null) {
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_ARTISTS)) {
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
long availableItems = 0;
Cursor cursor = null;
try {
availableItems = getNumItems(PATH_ARTISTS,
- MediaStore.Audio.Media.ARTIST_ID);
+ MediaStore.Audio.Media.ARTIST_ID, deviceIndex);
if (start >= availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
- if (DEBUG) Log.v(TAG, "availableItems: " + availableItems);
- if (DEBUG) Log.v(TAG, "reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "availableItems: " + availableItems);
+ if (DEBUG)
+ Log.v(TAG, "reqItems: " + reqItems);
availableItems = availableItems - start;
if (availableItems > MAX_BROWSE_ITEM_TO_SEND)
availableItems = MAX_BROWSE_ITEM_TO_SEND;
if (reqItems > availableItems)
reqItems = (int)availableItems;
- if (DEBUG) Log.v(TAG, "revised reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "revised reqItems: " + reqItems);
cursor = mContext.getContentResolver().query(
- mMediaUri, mCursorCols,
+ deviceFeatures[deviceIndex].mMediaUri, mCursorCols,
MediaStore.Audio.Media.IS_MUSIC + "=1", null,
MediaStore.Audio.Artists.DEFAULT_SORT_ORDER);
@@ -2620,8 +3412,10 @@ public final class Avrcp {
count = cursor.getCount();
} else {
Log.i(TAG, "Error: could not fetch the elements");
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
if (count < reqItems) {
@@ -2656,26 +3450,34 @@ public final class Avrcp {
}
if (index > 0) {
numItems = index;
- getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
} else {
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
}
- cursor.close();
} catch(Exception e) {
Log.i(TAG, "Exception e" + e);
- cursor.close();
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
} else {
- long folderUid = Long.valueOf(mCurrentPathUid);
+ long folderUid = Long.valueOf(deviceFeatures[deviceIndex].mCurrentPathUid);
long availableItems = 0;
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(
- mMediaUri,
+ deviceFeatures[deviceIndex].mMediaUri,
mCursorCols, MediaStore.Audio.Media.IS_MUSIC + "=1 AND " +
MediaStore.Audio.Media.ARTIST_ID + "=" + folderUid, null,
MediaStore.Audio.Artists.DEFAULT_SORT_ORDER);
@@ -2684,10 +3486,10 @@ public final class Avrcp {
availableItems = cursor.getCount();
if (start >= availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems,
- itemType, uid, type, playable, displayName, numAtt, attValues,
- attIds);
- cursor.close();
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
cursor.moveToFirst();
@@ -2696,19 +3498,24 @@ public final class Avrcp {
}
} else {
Log.i(TAG, "Error: could not fetch the elements");
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
- if (DEBUG) Log.v(TAG, "availableItems: " + availableItems);
- if (DEBUG) Log.v(TAG, "reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "availableItems: " + availableItems);
+ if (DEBUG)
+ Log.v(TAG, "reqItems: " + reqItems);
availableItems = availableItems - start;
if (availableItems > MAX_BROWSE_ITEM_TO_SEND)
availableItems = MAX_BROWSE_ITEM_TO_SEND;
if (reqItems > availableItems)
reqItems = availableItems;
- if (DEBUG) Log.v(TAG, "revised reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "revised reqItems: " + reqItems);
int attIndex;
int index;
@@ -2725,7 +3532,8 @@ public final class Avrcp {
if ((attrs[attIndex] <= MEDIA_ATTR_MAX) &&
(attrs[attIndex] >= MEDIA_ATTR_MIN)) {
attValues[(7 * index) + attIndex] =
- getAttributeStringFromCursor(cursor, attrs[attIndex]);
+ getAttributeStringFromCursor(
+ cursor, attrs[attIndex], deviceIndex);
attIds[(7 * index) + attIndex] = attrs[attIndex];
validAttrib ++;
}
@@ -2734,37 +3542,47 @@ public final class Avrcp {
cursor.moveToNext();
}
numItems = index;
- getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
- cursor.close();
+ getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
} catch(Exception e) {
Log.i(TAG, "Exception e" + e);
- cursor.close();
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType, uid,
- type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
- } else if (mCurrentPath.equals(PATH_PLAYLISTS)) {
- if (mCurrentPathUid == null) {
+ } else if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_PLAYLISTS)) {
+ if (deviceFeatures[deviceIndex].mCurrentPathUid == null) {
long availableItems = 0;
Cursor cursor = null;
try {
availableItems = getNumPlaylistItems();
if (start >= availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
-
- if (DEBUG) Log.v(TAG, "availableItems: " + availableItems);
- if (DEBUG) Log.v(TAG, "reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "availableItems: " + availableItems);
+ if (DEBUG)
+ Log.v(TAG, "reqItems: " + reqItems);
availableItems = availableItems - start;
if (availableItems > MAX_BROWSE_ITEM_TO_SEND)
availableItems = MAX_BROWSE_ITEM_TO_SEND;
if (reqItems > availableItems)
reqItems = (int)availableItems;
- if (DEBUG) Log.v(TAG, "revised reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "revised reqItems: " + reqItems);
String[] cols = new String[] {
MediaStore.Audio.Playlists._ID,
@@ -2781,8 +3599,10 @@ public final class Avrcp {
count = cursor.getCount();
} else {
Log.i(TAG, "Error: could not fetch the elements");
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
if (count < reqItems) {
@@ -2805,23 +3625,29 @@ public final class Avrcp {
if (index > 0) {
numItems = index;
- getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL, numItems,
- itemType, uid, type, playable, displayName, numAtt,
- attValues, attIds);
+ getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
} else {
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems,
- itemType, uid, type, playable, displayName, numAtt,
- attValues, attIds);
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
}
- cursor.close();
} catch(Exception e) {
Log.i(TAG, "Exception e" + e);
- cursor.close();
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
} else {
- long folderUid = Long.valueOf(mCurrentPathUid);
+ long folderUid = Long.valueOf(deviceFeatures[deviceIndex].mCurrentPathUid);
long availableItems = 0;
Cursor cursor = null;
@@ -2850,10 +3676,10 @@ public final class Avrcp {
availableItems = cursor.getCount();
if (start >= availableItems) {
Log.i(TAG, "startIteam exceeds the available item index");
- getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS, numItems,
- itemType, uid, type, playable, displayName, numAtt,
- attValues, attIds);
- cursor.close();
+ getFolderItemsRspNative((byte)RANGE_OUT_OF_BOUNDS ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
cursor.moveToFirst();
@@ -2862,19 +3688,24 @@ public final class Avrcp {
}
} else {
Log.i(TAG, "Error: could not fetch the elements");
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
return;
}
- if (DEBUG) Log.v(TAG, "availableItems: " + availableItems);
- if (DEBUG) Log.v(TAG, "reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "availableItems: " + availableItems);
+ if (DEBUG)
+ Log.v(TAG, "reqItems: " + reqItems);
availableItems = availableItems - start;
if (availableItems > MAX_BROWSE_ITEM_TO_SEND)
availableItems = MAX_BROWSE_ITEM_TO_SEND;
if (reqItems > availableItems)
reqItems = availableItems;
- if (DEBUG) Log.v(TAG, "revised reqItems: " + reqItems);
+ if (DEBUG)
+ Log.v(TAG, "revised reqItems: " + reqItems);
int attIndex;
int index;
@@ -2892,7 +3723,8 @@ public final class Avrcp {
if ((attrs[attIndex] <= MEDIA_ATTR_MAX) &&
(attrs[attIndex] >= MEDIA_ATTR_MIN)) {
attValues[(7 * index) + attIndex] =
- getAttributeStringFromCursor(cursor, attrs[attIndex]);
+ getAttributeStringFromCursor(
+ cursor, attrs[attIndex], deviceIndex);
attIds[(7 * index) + attIndex] = attrs[attIndex];
validAttrib ++;
}
@@ -2901,20 +3733,28 @@ public final class Avrcp {
cursor.moveToNext();
}
numItems = index;
- getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL, numItems, itemType, uid,
- type, playable, displayName, numAtt, attValues, attIds);
- cursor.close();
+ getFolderItemsRspNative((byte)OPERATION_SUCCESSFUL ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
} catch(Exception e) {
Log.e(TAG, "Exception e" + e);
- cursor.close();
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
} else {
- getFolderItemsRspNative((byte)DOES_NOT_EXIST, numItems, itemType, uid, type,
- playable, displayName, numAtt, attValues, attIds);
- Log.e(TAG, "GetFolderItems fail as player is not browsable");
+ getFolderItemsRspNative((byte)DOES_NOT_EXIST ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ Log.v(TAG, "GetFolderItems fail as player is not browsable");
}
} else if (scope == SCOPE_NOW_PLAYING) {
if (mMediaPlayers.size() > 0) {
@@ -2922,9 +3762,12 @@ public final class Avrcp {
while (rccIterator.hasNext()) {
final MediaPlayerInfo di = rccIterator.next();
if (di.GetPlayerFocus()) {
- if (!di.IsRemoteAddressable()) {
- getFolderItemsRspNative((byte)INTERNAL_ERROR, numItems, itemType,
- uid, type, playable, displayName, numAtt, attValues, attIds);
+ if (!di.IsRemoteAddressable() ||
+ deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_INVALID)) {
+ getFolderItemsRspNative((byte)INTERNAL_ERROR ,
+ numItems, itemType, uid, type,
+ playable, displayName, numAtt, attValues, attIds,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
Log.e(TAG, "GetFolderItems fails: addressed player is not browsable");
return;
}
@@ -2936,37 +3779,56 @@ public final class Avrcp {
}
}
- private void registerNotification(int eventId, int param) {
- Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_NOTIFICATION, eventId, param);
+ private void registerNotification(int eventId, int param, byte[] address) {
+ Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_NOTIFICATION, eventId,
+ param, Utils.getAddressStringFromByte(address));
mHandler.sendMessage(msg);
}
private void processRCCStateChange(String callingPackageName, int isFocussed, int isAvailable) {
- if (DEBUG) Log.v(TAG, "processRCCStateChange");
+ Log.v(TAG, "processRCCStateChange: " + callingPackageName);
boolean available = false;
boolean focussed = false;
boolean isResetFocusRequired = false;
-
+ BluetoothDevice device = null;
if (isFocussed == 1)
focussed = true;
if (isAvailable == 1)
available = true;
if (focussed) {
- isResetFocusRequired = true; // need to reset other player's focus.
- if (mRequestedAddressedPlayerPackageName != null) {
- if (callingPackageName.equals(mRequestedAddressedPlayerPackageName)) {
- mHandler.removeMessages(MESSAGE_SET_ADDR_PLAYER_REQ_TIMEOUT);
- if (DEBUG) Log.v(TAG, "SetAddressedPlayer succeeds for: "
- + mRequestedAddressedPlayerPackageName);
- mRequestedAddressedPlayerPackageName = null;
- setAdressedPlayerRspNative ((byte)OPERATION_SUCCESSFUL);
+ isResetFocusRequired = true;
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mRequestedAddressedPlayerPackageName != null) {
+ if (callingPackageName.equals(
+ deviceFeatures[i].mRequestedAddressedPlayerPackageName)) {
+ mHandler.removeMessages(MESSAGE_SET_ADDR_PLAYER_REQ_TIMEOUT);
+ if (deviceFeatures[i].isMusicAppResponsePending ==
+ true) {
+ device = deviceFeatures[i].mCurrentDevice;
+ deviceFeatures[i].isMusicAppResponsePending = false;
+ }
+ if (device == null) {
+ Log.e(TAG,"ERROR!!!! device is null");
+ return;
+ }
+
+ if (DEBUG)
+ Log.v(TAG, "SetAddressedPlayer succeeds for: "
+ + deviceFeatures[i].mRequestedAddressedPlayerPackageName);
+ deviceFeatures[i].mRequestedAddressedPlayerPackageName = null;
+ setAdressedPlayerRspNative((byte)OPERATION_SUCCESSFUL,
+ getByteAddress(deviceFeatures[i].mCurrentDevice));
+
+ } else {
+ if (DEBUG)
+ Log.v(TAG, "SetaddressedPlayer package mismatch with: "
+ + deviceFeatures[i].mRequestedAddressedPlayerPackageName);
+ }
} else {
- if (DEBUG) Log.v(TAG, "SetaddressedPlayer package mismatch with: "
- + mRequestedAddressedPlayerPackageName);
+ if (DEBUG)
+ Log.v(TAG, "SetaddressedPlayer request is not in progress");
}
- } else {
- if (DEBUG) Log.v(TAG, "SetaddressedPlayer request is not in progress");
}
}
@@ -2975,21 +3837,30 @@ public final class Avrcp {
while (rccIterator.hasNext()) {
final MediaPlayerInfo di = rccIterator.next();
if (di.RetrievePlayerPackageName().equals(callingPackageName)) {
+ isResetFocusRequired = false;
if (di.GetPlayerAvailablility() != available) {
di.SetPlayerAvailablility(available);
- if (DEBUG) Log.v(TAG, "setting " + callingPackageName + " availability: " + available);
+ if (DEBUG)
+ Log.v(TAG, "setting " + callingPackageName +
+ " availability: " + available);
if (mHandler != null) {
- if (DEBUG) Log.v(TAG, "Send MSG_UPDATE_AVAILABLE_PLAYERS");
- mHandler.obtainMessage(MSG_UPDATE_AVAILABLE_PLAYERS, 0, 0, 0).sendToTarget();
+ if (DEBUG)
+ Log.v(TAG, "Send MSG_UPDATE_AVAILABLE_PLAYERS");
+ mHandler.obtainMessage(MSG_UPDATE_AVAILABLE_PLAYERS,
+ 0, 0, 0).sendToTarget();
}
}
if (di.GetPlayerFocus() != focussed) {
di.SetPlayerFocus(focussed);
- if (DEBUG) Log.v(TAG, "setting " + callingPackageName + " focus: " + focussed);
- if(isResetFocusRequired) { // this ensures we got this message for fous on.
+ if (DEBUG)
+ Log.v(TAG, "setting " + callingPackageName + " focus: " + focussed);
+ if(focussed) {
if (mHandler != null) {
- if (DEBUG) Log.v(TAG, "Send MSG_UPDATE_ADDRESSED_PLAYER");
- mHandler.obtainMessage(MSG_UPDATE_ADDRESSED_PLAYER, di.RetrievePlayerId(), 0, 0).sendToTarget();
+ if (DEBUG)
+ Log.v(TAG, "Send MSG_UPDATE_ADDRESSED_PLAYER: " +
+ di.RetrievePlayerId());
+ mHandler.obtainMessage(MSG_UPDATE_ADDRESSED_PLAYER,
+ di.RetrievePlayerId(), 0, 0).sendToTarget();
}
}
}
@@ -2998,72 +3869,118 @@ public final class Avrcp {
}
}
- if (DEBUG) Log.v(TAG, "isResetFocusRequired: " + isResetFocusRequired);
+ if (DEBUG)
+ Log.v(TAG, "isResetFocusRequired: " + isResetFocusRequired);
- if (isResetFocusRequired) {
- if (mMediaPlayers.size() > 1) { // this is applicable only if list contains more than one media players
+ if (focussed) {
+ // this is applicable only if list contains more than one media players
+ if (mMediaPlayers.size() > 0) {
final Iterator<MediaPlayerInfo> rccIterator = mMediaPlayers.iterator();
while (rccIterator.hasNext()) {
final MediaPlayerInfo di = rccIterator.next();
if (!(di.RetrievePlayerPackageName().equals(callingPackageName))) {
- if (DEBUG) Log.v(TAG, "setting " + callingPackageName + " focus: false");
+ if (DEBUG)
+ Log.v(TAG, "setting " +
+ callingPackageName + " focus: false");
di.SetPlayerFocus(false); // reset focus for all other players
}
}
}
}
+
+ if(isResetFocusRequired) {
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (mHandler != null) {
+ if (DEBUG)
+ Log.v(TAG, "Send MSG_UPDATE_ADDRESSED_PLAYER: 0");
+ mHandler.obtainMessage(MSG_UPDATE_ADDRESSED_PLAYER,
+ 0, 0, 0).sendToTarget();
+ }
+ }
+ }
}
- private void processRegisterNotification(int eventId, int param) {
+ private void processRegisterNotification(int eventId, int param,
+ String deviceAddress) {
+ BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+ int deviceIndex = getIndexForDevice(device);
+ Log.v(TAG,"processRegisterNotification: eventId" + eventId);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.v(TAG,"device entry not present, bailing out");
+ return;
+ }
switch (eventId) {
case EVT_PLAY_STATUS_CHANGED:
- mPlayStatusChangedNT = NOTIFICATION_TYPE_INTERIM;
- registerNotificationRspPlayStatusNative(mPlayStatusChangedNT,
- convertPlayStateToPlayStatus(mCurrentPlayState));
+ deviceFeatures[deviceIndex].mPlayStatusChangedNT =
+ NOTIFICATION_TYPE_INTERIM;
+ registerNotificationRspPlayStatusNative(
+ deviceFeatures[deviceIndex].mPlayStatusChangedNT,
+ convertPlayStateToPlayStatus(
+ deviceFeatures[deviceIndex].mCurrentPlayState),
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
break;
case EVT_TRACK_CHANGED:
- mTrackChangedNT = NOTIFICATION_TYPE_INTERIM;
- sendTrackChangedRsp();
+ deviceFeatures[deviceIndex].mTrackChangedNT =
+ NOTIFICATION_TYPE_INTERIM;
+ sendTrackChangedRsp(device);
break;
case EVT_PLAY_POS_CHANGED:
- long songPosition = getPlayPosition();
- mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM;
- mPlaybackIntervalMs = (long)param * 1000L;
+ long songPosition = getPlayPosition(deviceFeatures[deviceIndex].mCurrentDevice);
+ deviceFeatures[deviceIndex].mPlayPosChangedNT = NOTIFICATION_TYPE_INTERIM;
+ deviceFeatures[deviceIndex].mPlaybackIntervalMs = (long)param * 1000L;
if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
- mNextPosMs = songPosition + mPlaybackIntervalMs;
- mPrevPosMs = songPosition - mPlaybackIntervalMs;
- if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
- Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT);
- mHandler.sendMessageDelayed(msg, mPlaybackIntervalMs);
+ deviceFeatures[deviceIndex].mNextPosMs = songPosition +
+ deviceFeatures[deviceIndex].mPlaybackIntervalMs;
+ deviceFeatures[deviceIndex].mPrevPosMs = songPosition -
+ deviceFeatures[deviceIndex].mPlaybackIntervalMs;
+ if (deviceFeatures[deviceIndex].mCurrentPlayState ==
+ RemoteControlClient.PLAYSTATE_PLAYING) {
+ Message msg = mHandler.obtainMessage(MESSAGE_PLAY_INTERVAL_TIMEOUT,
+ 0, 0, deviceFeatures[deviceIndex].mCurrentDevice);
+ mHandler.sendMessageDelayed(msg,
+ deviceFeatures[deviceIndex].mPlaybackIntervalMs);
}
}
- registerNotificationRspPlayPosNative(mPlayPosChangedNT, (int)songPosition);
+ registerNotificationRspPlayPosNative(deviceFeatures[deviceIndex].mPlayPosChangedNT,
+ (int)getPlayPosition(deviceFeatures[deviceIndex].mCurrentDevice) ,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
+ if (DEBUG)
+ Log.v(TAG,"mPlayPosChangedNT updated for index " +
+ deviceFeatures[deviceIndex].mPlayPosChangedNT +
+ " index " + deviceIndex);
break;
-
case EVT_APP_SETTINGS_CHANGED:
- mPlayerStatusChangeNT = NOTIFICATION_TYPE_INTERIM;
- sendPlayerAppChangedRsp(mPlayerStatusChangeNT);
+ deviceFeatures[deviceIndex].mPlayerStatusChangeNT = NOTIFICATION_TYPE_INTERIM;
+ sendPlayerAppChangedRsp(deviceFeatures[deviceIndex].mPlayerStatusChangeNT,
+ device);
break;
case EVT_ADDRESSED_PLAYER_CHANGED:
- if (DEBUG) Log.v(TAG, "Process EVT_ADDRESSED_PLAYER_CHANGED Interim: Player ID: " + mAddressedPlayerId);
- mAddressedPlayerChangedNT = NOTIFICATION_TYPE_INTERIM;
- registerNotificationRspAddressedPlayerChangedNative(mAddressedPlayerChangedNT, mAddressedPlayerId);
+ if (DEBUG)
+ Log.v(TAG, "Process EVT_ADDRESSED_PLAYER_CHANGED Interim: Player ID: "
+ + mAddressedPlayerId);
+ deviceFeatures[deviceIndex].mAddressedPlayerChangedNT = NOTIFICATION_TYPE_INTERIM;
+ registerNotificationRspAddressedPlayerChangedNative(
+ deviceFeatures[deviceIndex].mAddressedPlayerChangedNT ,
+ mAddressedPlayerId ,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
break;
case EVT_AVAILABLE_PLAYERS_CHANGED:
- if (DEBUG) Log.v(TAG, "Process EVT_AVAILABLE_PLAYERS_CHANGED Interim");
- mAvailablePlayersChangedNT = NOTIFICATION_TYPE_INTERIM;
- registerNotificationRspAvailablePlayersChangedNative(mAvailablePlayersChangedNT);
+ deviceFeatures[deviceIndex].mAvailablePlayersChangedNT = NOTIFICATION_TYPE_INTERIM;
+ registerNotificationRspAvailablePlayersChangedNative(
+ deviceFeatures[deviceIndex].mAvailablePlayersChangedNT,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
break;
case EVT_NOW_PLAYING_CONTENT_CHANGED:
- if (DEBUG) Log.v(TAG, "Process EVT_NOW_PLAYING_CONTENT_CHANGED Interim");
- mNowPlayingContentChangedNT = NOTIFICATION_TYPE_INTERIM;
- registerNotificationRspNowPlayingContentChangedNative(mNowPlayingContentChangedNT);
+ deviceFeatures[deviceIndex].mNowPlayingContentChangedNT = NOTIFICATION_TYPE_INTERIM;
+ registerNotificationRspNowPlayingContentChangedNative(
+ deviceFeatures[deviceIndex].mNowPlayingContentChangedNT ,
+ getByteAddress(deviceFeatures[deviceIndex].mCurrentDevice));
break;
default:
@@ -3072,19 +3989,20 @@ public final class Avrcp {
}
}
- private void handlePassthroughCmd(int id, int keyState) {
+ private void handlePassthroughCmd(int id, int keyState,
+ byte[] address) {
switch (id) {
case BluetoothAvrcp.PASSTHROUGH_ID_REWIND:
- rewind(keyState);
+ rewind(keyState, Utils.getAddressStringFromByte(address));
break;
case BluetoothAvrcp.PASSTHROUGH_ID_FAST_FOR:
- fastForward(keyState);
+ fastForward(keyState, Utils.getAddressStringFromByte(address));
break;
}
}
- private void changePositionBy(long amount) {
- long currentPosMs = getPlayPosition();
+ private void changePositionBy(long amount, String deviceAddress) {
+ long currentPosMs = getPlayPosition(mAdapter.getRemoteDevice(deviceAddress));
if (currentPosMs == -1L) return;
long newPosMs = Math.max(0L, currentPosMs + amount);
mRemoteController.seekTo(newPosMs);
@@ -3096,25 +4014,25 @@ public final class Avrcp {
return (int) Math.min(MAX_MULTIPLIER_VALUE, multi);
}
- private void sendTrackChangedRsp() {
+ private void sendTrackChangedRsp(BluetoothDevice device) {
byte[] track = new byte[TRACK_ID_SIZE];
+ long TrackNumberRsp = -1L;
+ int deviceIndex = getIndexForDevice(device);
+ if(DEBUG) Log.v(TAG,"mCurrentPlayState" +
+ deviceFeatures[deviceIndex].mCurrentPlayState );
- /* If no track is currently selected, then return
- 0xFFFFFFFFFFFFFFFF in the interim response */
- long trackNumberRsp = -1L;
-
- if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
- trackNumberRsp = mTrackNumber;
- }
+ TrackNumberRsp = mMetadata.tracknum ;
/* track is stored in big endian format */
for (int i = 0; i < TRACK_ID_SIZE; ++i) {
- track[i] = (byte) (trackNumberRsp >> (56 - 8 * i));
+ track[i] = (byte) (TrackNumberRsp >> (56 - 8 * i));
}
- registerNotificationRspTrackChangeNative(mTrackChangedNT, track);
+ registerNotificationRspTrackChangeNative(deviceFeatures[deviceIndex].mTrackChangedNT ,
+ track ,getByteAddress(device));
+
}
- private void sendPlayerAppChangedRsp(int rsptype) {
+ private void sendPlayerAppChangedRsp(int rsptype, BluetoothDevice device) {
int j = 0;
byte i = NUMPLAYER_ATTRIBUTE*2;
byte [] retVal = new byte [i];
@@ -3122,24 +4040,44 @@ public final class Avrcp {
retVal[j++] = settingValues.repeat_value;
retVal[j++] = ATTRIBUTE_SHUFFLEMODE;
retVal[j++] = settingValues.shuffle_value;
- registerNotificationPlayerAppRspNative(rsptype, i, retVal);
+ registerNotificationPlayerAppRspNative(rsptype,
+ i, retVal,
+ getByteAddress(device));
}
- private long getPlayPosition() {
+ private long getPlayPosition(BluetoothDevice device) {
long songPosition = -1L;
- if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
- if (mCurrentPlayState == RemoteControlClient.PLAYSTATE_PLAYING) {
- songPosition = SystemClock.elapsedRealtime() -
- mPlayStartTimeMs + mCurrentPosMs;
- } else {
- songPosition = mCurrentPosMs;
+ if (device != null) {
+ int deviceIndex = getIndexForDevice(device);
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"Device index is not valid in getPlayPosition");
+ return songPosition;
+ }
+ if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+ if (deviceFeatures[deviceIndex].mCurrentPlayState ==
+ RemoteControlClient.PLAYSTATE_PLAYING) {
+ songPosition = SystemClock.elapsedRealtime() - mPlayStartTimeMs +
+ mCurrentPosMs;
+ } else {
+ songPosition = mCurrentPosMs;
+ }
+ }
+ } else {
+ if (mCurrentPosMs != RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
+ if (mCurrentPlayerState == RemoteControlClient.PLAYSTATE_PLAYING) {
+ songPosition = SystemClock.elapsedRealtime() -
+ mPlayStartTimeMs + mCurrentPosMs;
+ } else {
+ songPosition = mCurrentPosMs;
+ }
}
}
- if (DEBUG) Log.v(TAG, "position=" + songPosition);
+ if (DEBUG) Log.v(TAG, "getPlayPosition position: " + songPosition + " Device:"
+ + device);
return songPosition;
}
- private String getAttributeStringFromCursor(Cursor cursor, int attrId) {
+ private String getAttributeStringFromCursor(Cursor cursor, int attrId, int deviceIndex) {
String attrStr = "<unknown>";
switch (attrId) {
case MEDIA_ATTR_TITLE:
@@ -3159,7 +4097,7 @@ public final class Avrcp {
MediaStore.Audio.Media.DURATION));
break;
case MEDIA_ATTR_TRACK_NUM:
- if (mCurrentPath.equals(PATH_PLAYLISTS)) {
+ if (deviceFeatures[deviceIndex].mCurrentPath.equals(PATH_PLAYLISTS)) {
attrStr = cursor.getString(cursor.getColumnIndexOrThrow(
MediaStore.Audio.Playlists.Members._ID));
} else {
@@ -3181,8 +4119,9 @@ public final class Avrcp {
if (attrStr == null) {
attrStr = new String();
}
- if (DEBUG) Log.v(TAG, "getAttributeStringFromCursor: attrId = "
- + attrId + " str = " + attrStr);
+ if (DEBUG)
+ Log.v(TAG, "getAttributeStringFromCursor: attrId = "
+ + attrId + " str = " + attrStr);
return attrStr;
}
@@ -3223,7 +4162,8 @@ public final class Avrcp {
if (attrStr == null) {
attrStr = new String();
}
- if (DEBUG) Log.v(TAG, "getAttributeString:attrId=" + attrId + " str=" + attrStr);
+ if (DEBUG)
+ Log.v(TAG, "getAttributeString:attrId=" + attrId + " str=" + attrStr);
return attrStr;
}
@@ -3279,9 +4219,25 @@ public final class Avrcp {
/**
* This is called from AudioService. It will return whether this device supports abs volume.
* NOT USED AT THE MOMENT.
+ * returns true only when both playing devices support absolute volume
*/
public boolean isAbsoluteVolumeSupported() {
- return ((mFeatures & BTRC_FEAT_ABSOLUTE_VOLUME) != 0);
+ List<Byte> absVolumeSupported = new ArrayList<Byte>();
+ for (int i = 0; i < maxAvrcpConnections; i++ ) {
+ if (deviceFeatures[i].mCurrentDevice != null) {
+ // add 1 in byte list if absolute volume is supported
+ // add 0 in byte list if absolute volume not supported
+ if ((deviceFeatures[i].mFeatures &
+ BTRC_FEAT_ABSOLUTE_VOLUME) != 0) {
+ Log.v(TAG, "isAbsoluteVolumeSupported: yes, for dev: " + i);
+ absVolumeSupported.add((byte)1);
+ } else {
+ Log.v(TAG, "isAbsoluteVolumeSupported: no, for dev: " + i);
+ absVolumeSupported.add((byte)0);
+ }
+ }
+ }
+ return !absVolumeSupported.contains((byte)0);
}
/**
@@ -3308,12 +4264,13 @@ public final class Avrcp {
* This method will send a message to our handler to change the local stored volume and notify
* AudioService to update the UI
*/
- private void volumeChangeCallback(int volume, int ctype) {
- Message msg = mHandler.obtainMessage(MESSAGE_VOLUME_CHANGED, volume, ctype);
+ private void volumeChangeCallback(int volume, int ctype, byte[] address) {
+ Message msg = mHandler.obtainMessage(MESSAGE_VOLUME_CHANGED, volume,
+ ctype, Utils.getAddressStringFromByte(address));
mHandler.sendMessage(msg);
}
- private void notifyVolumeChanged(int volume) {
+ private void notifyVolumeChanged(int volume, BluetoothDevice device) {
volume = convertToAudioStreamVolume(volume);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
@@ -3357,6 +4314,7 @@ public final class Avrcp {
switch (data[i]) {
case ATTRIBUTE_EQUALIZER:
if (mPendingSetAttributes.contains(new Integer(ATTRIBUTE_EQUALIZER))) {
+ Log.v(TAG, "Pending SetAttribute contains Equalizer");
if(data[i+1] == ATTRIBUTE_NOTSUPPORTED) {
ret = false;
} else {
@@ -3366,6 +4324,7 @@ public final class Avrcp {
break;
case ATTRIBUTE_REPEATMODE:
if (mPendingSetAttributes.contains(new Integer(ATTRIBUTE_REPEATMODE))) {
+ Log.v(TAG, "Pending SetAttribute contains Repeat");
if(data[i+1] == ATTRIBUTE_NOTSUPPORTED) {
ret = false;
} else {
@@ -3375,6 +4334,7 @@ public final class Avrcp {
break;
case ATTRIBUTE_SHUFFLEMODE:
if (mPendingSetAttributes.contains(new Integer(ATTRIBUTE_SHUFFLEMODE))) {
+ Log.v(TAG, "Pending SetAttribute contains Shuffle");
if(data[i+1] == ATTRIBUTE_NOTSUPPORTED) {
ret = false;
} else {
@@ -3384,44 +4344,67 @@ public final class Avrcp {
break;
}
}
- mPendingSetAttributes.clear();
return ret;
}
//PDU ID 0x11
- private void onListPlayerAttributeRequest() {
- if (DEBUG) Log.v(TAG, "onListPlayerAttributeRequest");
+ private void onListPlayerAttributeRequest(byte[] address) {
+ if (DEBUG)
+ Log.v(TAG, "onListPlayerAttributeRequest");
Intent intent = new Intent(PLAYERSETTINGS_REQUEST);
intent.putExtra(COMMAND, CMDGET);
intent.putExtra(EXTRA_GET_COMMAND, GET_ATTRIBUTE_IDS);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
-
- Message msg = mHandler.obtainMessage(MESSAGE_PLAYERSETTINGS_TIMEOUT ,GET_ATTRIBUTE_IDS );
+ int deviceIndex =
+ getIndexForDevice(mAdapter.getRemoteDevice(
+ Utils.getAddressStringFromByte(address)));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+ deviceFeatures[deviceIndex].isMusicAppResponsePending = true;
+ Message msg = mHandler.obtainMessage(MESSAGE_PLAYERSETTINGS_TIMEOUT,
+ GET_ATTRIBUTE_IDS,0 ,
+ Utils.getAddressStringFromByte(address));
mPendingCmds.add(new Integer(msg.arg1));
- mHandler.sendMessageDelayed(msg, 130);
+ mHandler.sendMessageDelayed(msg, 500);
}
//PDU ID 0x12
- private void onListPlayerAttributeValues (byte attr ) {
- if (DEBUG) Log.v(TAG, "onListPlayerAttributeValues");
+ private void onListPlayerAttributeValues (byte attr, byte[] address) {
+ if (DEBUG)Log.v(TAG, "onListPlayerAttributeValues");
Intent intent = new Intent(PLAYERSETTINGS_REQUEST);
intent.putExtra(COMMAND, CMDGET);
intent.putExtra(EXTRA_GET_COMMAND, GET_VALUE_IDS);
intent.putExtra(EXTRA_ATTRIBUTE_ID, attr);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mPlayerSettings.attr = attr;
+ int deviceIndex =
+ getIndexForDevice(mAdapter.getRemoteDevice(
+ Utils.getAddressStringFromByte(address)));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+
+ deviceFeatures[deviceIndex].isMusicAppResponsePending = true;
+
Message msg = mHandler.obtainMessage();
msg.what = MESSAGE_PLAYERSETTINGS_TIMEOUT;
msg.arg1 = GET_VALUE_IDS;
+ msg.arg2 = 0;
+ msg.obj = Utils.getAddressStringFromByte(address);
mPendingCmds.add(new Integer(msg.arg1));
- mHandler.sendMessageDelayed(msg, 130);
+ mHandler.sendMessageDelayed(msg, 500);
}
//PDU ID 0x13
- private void onGetPlayerAttributeValues (byte attr ,int[] arr )
+ private void onGetPlayerAttributeValues (byte attr ,int[] arr ,
+ byte[] address)
{
- if (DEBUG) Log.v(TAG, "onGetPlayerAttributeValues" + attr );
+ if (DEBUG)
+ Log.v(TAG, "onGetPlayerAttributeValues: num of attrib " + attr );
int i ;
byte[] barray = new byte[attr];
for(i =0 ; i<attr ; ++i)
@@ -3434,17 +4417,30 @@ public final class Avrcp {
intent.putExtra(EXTRA_GET_COMMAND, GET_ATTRIBUTE_VALUES);
intent.putExtra(EXTRA_ATTIBUTE_ID_ARRAY, barray);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ int deviceIndex =
+ getIndexForDevice(mAdapter.getRemoteDevice(
+ Utils.getAddressStringFromByte(address)));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+ deviceFeatures[deviceIndex].isMusicAppResponsePending = true;
+
Message msg = mHandler.obtainMessage();
msg.what = MESSAGE_PLAYERSETTINGS_TIMEOUT;
msg.arg1 = GET_ATTRIBUTE_VALUES;
+ msg.arg2 = 0;
+ msg.obj = Utils.getAddressStringFromByte(address);
mPendingCmds.add(new Integer(msg.arg1));
- mHandler.sendMessageDelayed(msg, 130);
+ mHandler.sendMessageDelayed(msg, 500);
}
//PDU 0x14
- private void setPlayerAppSetting( byte num , byte [] attr_id , byte [] attr_val )
+ private void setPlayerAppSetting( byte num, byte [] attr_id, byte [] attr_val,
+ byte[] address)
{
- if (DEBUG) Log.v(TAG, "setPlayerAppSetting " + num );
+ if (DEBUG)
+ Log.v(TAG, "setPlayerAppSetting: number of attributes" + num );
byte[] array = new byte[num*2];
for ( int i = 0; i < num; i++)
{
@@ -3456,17 +4452,31 @@ public final class Avrcp {
intent.putExtra(COMMAND, CMDSET);
intent.putExtra(EXTRA_ATTRIB_VALUE_PAIRS, array);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ int deviceIndex =
+ getIndexForDevice(mAdapter.getRemoteDevice(
+ Utils.getAddressStringFromByte(address)));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+
+ deviceFeatures[deviceIndex].isMusicAppResponsePending = true;
+
Message msg = mHandler.obtainMessage();
msg.what = MESSAGE_PLAYERSETTINGS_TIMEOUT;
msg.arg1 = SET_ATTRIBUTE_VALUES;
+ msg.arg2 = 0;
+ msg.obj = Utils.getAddressStringFromByte(address);
mPendingCmds.add(new Integer(msg.arg1));
mHandler.sendMessageDelayed(msg, 500);
}
//PDU 0x15
- private void getplayerattribute_text(byte attr , byte [] attrIds)
+ private void getplayerattribute_text(byte attr , byte [] attrIds,
+ byte[] address)
{
- if(DEBUG) Log.d(TAG, "getplayerattribute_text" + attr +"attrIDsNum" + attrIds.length);
+ if(DEBUG) Log.d(TAG, "getplayerattribute_text " + attr +" attrIDsNum "
+ + attrIds.length);
Intent intent = new Intent(PLAYERSETTINGS_REQUEST);
Message msg = mHandler.obtainMessage();
intent.putExtra(COMMAND, CMDGET);
@@ -3476,17 +4486,30 @@ public final class Avrcp {
for (int i = 0; i < attr; i++)
mPlayerSettings.attrIds[i] = attrIds[i];
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+ int deviceIndex =
+ getIndexForDevice(mAdapter.getRemoteDevice(
+ Utils.getAddressStringFromByte(address)));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+
+ deviceFeatures[deviceIndex].isMusicAppResponsePending = true;
+
msg.what = MESSAGE_PLAYERSETTINGS_TIMEOUT;
msg.arg1 = GET_ATTRIBUTE_TEXT;
+ msg.arg2 = 0;
+ msg.obj = Utils.getAddressStringFromByte(address);
mPendingCmds.add(new Integer(msg.arg1));
- mHandler.sendMessageDelayed(msg, 130);
+ mHandler.sendMessageDelayed(msg, 500);
}
//PDU 0x15
- private void getplayervalue_text(byte attr_id , byte num_value , byte [] value)
+ private void getplayervalue_text(byte attr_id , byte num_value , byte [] value,
+ byte[] address)
{
- if(DEBUG) Log.d(TAG, "getplayervalue_text id" + attr_id +"num_value" + num_value
- +"value.lenght" + value.length);
+ if(DEBUG) Log.d(TAG, "getplayervalue_text id " + attr_id +" num_value " + num_value
+ +" length " + value.length);
Intent intent = new Intent(PLAYERSETTINGS_REQUEST);
Message msg = mHandler.obtainMessage();
intent.putExtra(COMMAND, CMDGET);
@@ -3494,49 +4517,193 @@ public final class Avrcp {
intent.putExtra(EXTRA_ATTRIBUTE_ID, attr_id);
intent.putExtra(EXTRA_VALUE_ID_ARRAY, value);
mPlayerSettings.attrIds = new byte [num_value];
+ int deviceIndex =
+ getIndexForDevice(mAdapter.getRemoteDevice(
+ Utils.getAddressStringFromByte(address)));
+ if (deviceIndex == INVALID_DEVICE_INDEX) {
+ Log.e(TAG,"invalid index for device");
+ return;
+ }
+ deviceFeatures[deviceIndex].isMusicAppResponsePending = true;
for (int i = 0; i < num_value; i++)
mPlayerSettings.attrIds[i] = value[i];
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
msg.what = MESSAGE_PLAYERSETTINGS_TIMEOUT;
msg.arg1 = GET_VALUE_TEXT;
+ msg.arg2 = 0;
+ msg.obj = Utils.getAddressStringFromByte(address);
mPendingCmds.add(new Integer(msg.arg1));
- mHandler.sendMessageDelayed(msg, 130);
+ mHandler.sendMessageDelayed(msg, 500);
}
/**
* This is called from A2dpStateMachine to set A2dp audio state.
*/
- public void setA2dpAudioState(int state) {
- Message msg = mHandler.obtainMessage(MESSAGE_SET_A2DP_AUDIO_STATE, state, 0);
+ public void setA2dpAudioState(int state, BluetoothDevice device) {
+ Message msg = mHandler.obtainMessage(MESSAGE_SET_A2DP_AUDIO_STATE, state,
+ 0, device);
mHandler.sendMessage(msg);
}
+ public void setAvrcpConnectedDevice(BluetoothDevice device) {
+ Log.i(TAG,"Device added is " + device);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mCurrentDevice != null &&
+ deviceFeatures[i].mCurrentDevice.equals(device)) {
+ Log.v(TAG,"device is already added in connected list, ignore now");
+ return;
+ }
+ }
+ for (int i = 0; i < maxAvrcpConnections; i++ ) {
+ if (deviceFeatures[i].mCurrentDevice == null) {
+ deviceFeatures[i].mCurrentDevice = device;
+ /*Playstate is explicitly updated here to take care of cases
+ where play state update is missed because of that happening
+ even before Avrcp connects*/
+ deviceFeatures[i].mCurrentPlayState = mCurrentPlayerState;
+ Log.i(TAG,"play status updated on Avrcp connection as: " +
+ mCurrentPlayerState);
+ Log.i(TAG,"device added at " + i);
+ break;
+ }
+ }
+ }
+
+ public boolean isAvrcpConnected() {
+ boolean ret = false;
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mCurrentDevice != null) {
+ ret = true;
+ break;
+ }
+ }
+ Log.i(TAG,"isAvrcpConnected: " + ret);
+ return ret;
+ }
+
+ private int getIndexForDevice(BluetoothDevice device) {
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ if (deviceFeatures[i].mCurrentDevice != null &&
+ deviceFeatures[i].mCurrentDevice.equals(device)) {
+ Log.i(TAG,"device found at index " + i);
+ return i;
+ }
+ }
+ Log.e(TAG, "returning invalid index");
+ return INVALID_DEVICE_INDEX;
+ }
+
+ public void cleanupDeviceFeaturesIndex (int index) {
+ Log.i(TAG,"cleanupDeviceFeaturesIndex index:" + index);
+ deviceFeatures[index].mCurrentDevice = null;
+ deviceFeatures[index].mCurrentPlayState = RemoteControlClient.PLAYSTATE_NONE;
+ deviceFeatures[index].mPlayStatusChangedNT = NOTIFICATION_TYPE_CHANGED;
+ deviceFeatures[index].mPlayerStatusChangeNT = NOTIFICATION_TYPE_CHANGED;
+ deviceFeatures[index].mTrackChangedNT = NOTIFICATION_TYPE_CHANGED;
+ deviceFeatures[index].mPlaybackIntervalMs = 0L;
+ deviceFeatures[index].mPlayPosChangedNT = NOTIFICATION_TYPE_CHANGED;
+ deviceFeatures[index].mFeatures = 0;
+ deviceFeatures[index].mAbsoluteVolume = -1;
+ deviceFeatures[index].mLastSetVolume = -1;
+ deviceFeatures[index].mLastDirection = 0;
+ deviceFeatures[index].mVolCmdInProgress = false;
+ deviceFeatures[index].mAbsVolRetryTimes = 0;
+ deviceFeatures[index].keyPressState = KEY_STATE_RELEASE; //Key release state
+ deviceFeatures[index].mAddressedPlayerChangedNT = NOTIFICATION_TYPE_CHANGED;
+ deviceFeatures[index].mAvailablePlayersChangedNT = NOTIFICATION_TYPE_CHANGED;
+ deviceFeatures[index].mNowPlayingContentChangedNT = NOTIFICATION_TYPE_CHANGED;
+ deviceFeatures[index].mRequestedAddressedPlayerPackageName = null;
+ deviceFeatures[index].mCurrentPath = PATH_INVALID;
+ deviceFeatures[index].mCurrentPathUid = null;
+ deviceFeatures[index].mMediaUri = Uri.EMPTY;
+ deviceFeatures[index].isMusicAppResponsePending = false;
+ deviceFeatures[index].isBrowsingSupported = false;
+ deviceFeatures[index].isAbsoluteVolumeSupportingDevice = false;
+ }
+ /**
+ * This is called from A2dpStateMachine to set A2dp Connected device to null on disconnect.
+ */
+ public void setAvrcpDisconnectedDevice(BluetoothDevice device) {
+ for (int i = 0; i < maxAvrcpConnections; i++ ) {
+ if (deviceFeatures[i].mCurrentDevice !=null &&
+ deviceFeatures[i].mCurrentDevice.equals(device)) {
+ // initiate cleanup for all variables;
+ Log.i(TAG,"Device removed is " + device);
+ Log.i(TAG,"removed at " + i);
+ deviceFeatures[i].mCurrentDevice = null;
+ cleanupDeviceFeaturesIndex(i);
+ /* device is disconnect and some response form music app was
+ * pending for this device clear it.*/
+ if (mBrowserDevice != null &&
+ mBrowserDevice.equals(device)) {
+ Log.i(TAG,"clearing mBrowserDevice on disconnect");
+ mBrowserDevice = null;
+ }
+ break;
+ }
+ }
+ mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(),
+ isAbsoluteVolumeSupported());
+ Log.v(TAG," update audio manager for abs vol state = "
+ + isAbsoluteVolumeSupported());
+ for (int i = 0; i < maxAvrcpConnections; i++ ) {
+ if (deviceFeatures[i].mCurrentDevice != null) {
+ if (isAbsoluteVolumeSupported() &&
+ deviceFeatures[i].mAbsoluteVolume != -1) {
+ notifyVolumeChanged(deviceFeatures[i].mAbsoluteVolume,
+ deviceFeatures[i].mCurrentDevice);
+ Log.v(TAG," update audio manager for abs vol = "
+ + deviceFeatures[i].mAbsoluteVolume);
+ }
+ break;
+ }
+ }
+ }
+
+ private byte[] getByteAddress(BluetoothDevice device) {
+ return Utils.getBytesFromAddress(device.getAddress());
+ }
+
+ private void onConnectionStateChanged(boolean connected, byte[] address) {
+ BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice
+ (Utils.getAddressStringFromByte(address));
+ Log.d(TAG, "onConnectionStateChanged state: " + connected + " Addr: " + device);
+ if (connected) {
+ setAvrcpConnectedDevice(device);
+ } else {
+ setAvrcpDisconnectedDevice(device);
+ }
+ }
+
public void dump(StringBuilder sb) {
sb.append("AVRCP:\n");
- ProfileService.println(sb, "mMetadata: " + mMetadata);
- ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags);
- ProfileService.println(sb, "mCurrentPlayState: " + mCurrentPlayState);
- ProfileService.println(sb, "mPlayStatusChangedNT: " + mPlayStatusChangedNT);
- ProfileService.println(sb, "mTrackChangedNT: " + mTrackChangedNT);
- ProfileService.println(sb, "mTrackNumber: " + mTrackNumber);
- ProfileService.println(sb, "mCurrentPosMs: " + mCurrentPosMs);
- ProfileService.println(sb, "mPlayStartTimeMs: " + mPlayStartTimeMs);
- ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs);
- ProfileService.println(sb, "mPlaybackIntervalMs: " + mPlaybackIntervalMs);
- ProfileService.println(sb, "mPlayPosChangedNT: " + mPlayPosChangedNT);
- ProfileService.println(sb, "mNextPosMs: " + mNextPosMs);
- ProfileService.println(sb, "mPrevPosMs: " + mPrevPosMs);
- ProfileService.println(sb, "mSkipStartTime: " + mSkipStartTime);
- ProfileService.println(sb, "mFeatures: " + mFeatures);
- ProfileService.println(sb, "mAbsoluteVolume: " + mAbsoluteVolume);
- ProfileService.println(sb, "mLastSetVolume: " + mLastSetVolume);
- ProfileService.println(sb, "mLastDirection: " + mLastDirection);
- ProfileService.println(sb, "mVolumeStep: " + mVolumeStep);
- ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax);
- ProfileService.println(sb, "mVolCmdInProgress: " + mVolCmdInProgress);
- ProfileService.println(sb, "mAbsVolRetryTimes: " + mAbsVolRetryTimes);
- ProfileService.println(sb, "mSkipAmount: " + mSkipAmount);
+ for (int i = 0; i < maxAvrcpConnections; i++) {
+ Log.v(TAG,"for index " + i);
+ ProfileService.println(sb, "mMetadata: " + mMetadata);
+ ProfileService.println(sb, "mTransportControlFlags: " + mTransportControlFlags);
+ ProfileService.println(sb, "mCurrentPlayState: " + deviceFeatures[i].mCurrentPlayState);
+ ProfileService.println(sb, "mPlayStatusChangedNT: " + deviceFeatures[i].mPlayStatusChangedNT);
+ ProfileService.println(sb, "mTrackChangedNT: " + deviceFeatures[i].mTrackChangedNT);
+ ProfileService.println(sb, "mTrackNumber: " + mTrackNumber);
+ ProfileService.println(sb, "mCurrentPosMs: " + mCurrentPosMs);
+ ProfileService.println(sb, "mPlayStartTimeMs: " + mPlayStartTimeMs);
+ ProfileService.println(sb, "mSongLengthMs: " + mSongLengthMs);
+ ProfileService.println(sb, "mPlaybackIntervalMs: " + deviceFeatures[i].mPlaybackIntervalMs);
+ ProfileService.println(sb, "mPlayPosChangedNT: " + deviceFeatures[i].mPlayPosChangedNT);
+ ProfileService.println(sb, "mNextPosMs: " + deviceFeatures[i].mNextPosMs);
+ ProfileService.println(sb, "mPrevPosMs: " + deviceFeatures[i].mPrevPosMs);
+ ProfileService.println(sb, "mSkipStartTime: " + mSkipStartTime);
+ ProfileService.println(sb, "mFeatures: " + deviceFeatures[i].mFeatures);
+ ProfileService.println(sb, "mAbsoluteVolume: " + deviceFeatures[i].mAbsoluteVolume);
+ ProfileService.println(sb, "mLastSetVolume: " + deviceFeatures[i].mLastSetVolume);
+ ProfileService.println(sb, "mLastDirection: " + deviceFeatures[i].mLastDirection);
+ ProfileService.println(sb, "mVolumeStep: " + mVolumeStep);
+ ProfileService.println(sb, "mAudioStreamMax: " + mAudioStreamMax);
+ ProfileService.println(sb, "mVolCmdInProgress: " + deviceFeatures[i].mVolCmdInProgress);
+ ProfileService.println(sb, "mAbsVolRetryTimes: " + deviceFeatures[i].mAbsVolRetryTimes);
+ ProfileService.println(sb, "mSkipAmount: " + mSkipAmount);
+ }
}
// Do not modify without updating the HAL bt_rc.h files.
@@ -3882,41 +5049,53 @@ public final class Avrcp {
final static short ITEM_TYPE_LENGTH = 1;
final static short ITEM_LENGTH_LENGTH = 2;
private native static void classInitNative();
- private native void initNative();
+ private native void initNative(int maxConnections);
private native void cleanupNative();
- private native boolean getPlayStatusRspNative(int playStatus, int songLen, int songPos);
- private native boolean getElementAttrRspNative(byte numAttr, int[] attrIds, String[] textArray);
- private native boolean registerNotificationRspPlayStatusNative(int type, int playStatus);
- private native boolean registerNotificationRspTrackChangeNative(int type, byte[] track);
- private native boolean registerNotificationRspPlayPosNative(int type, int playPos);
- private native boolean setVolumeNative(int volume);
- private native boolean sendPassThroughCommandNative(int keyCode, int keyState);
+ private native boolean getPlayStatusRspNative(int playStatus, int songLen, int
+ songPos, byte[] address);
+ private native boolean getElementAttrRspNative(byte numAttr, int[] attrIds, String[]
+ textArray, byte[] address);
+ private native boolean registerNotificationRspPlayStatusNative(int type, int
+ playStatus, byte[] address);
+ private native boolean registerNotificationRspTrackChangeNative(int type, byte[]
+ track, byte[] address);
+ private native boolean registerNotificationRspPlayPosNative(int type, int
+ playPos, byte[] address);
+ private native boolean setVolumeNative(int volume, byte[] address);
private native boolean registerNotificationRspAddressedPlayerChangedNative(
- int type, int playerId);
- private native boolean registerNotificationRspAvailablePlayersChangedNative(int type);
- private native boolean registerNotificationRspNowPlayingContentChangedNative(int type);
- private native boolean setAdressedPlayerRspNative(byte statusCode);
+ int type, int playerId, byte[] address);
+ private native boolean registerNotificationRspAvailablePlayersChangedNative(
+ int type, byte[] address);
+ private native boolean registerNotificationRspNowPlayingContentChangedNative(
+ int type, byte[] address);
+ private native boolean setAdressedPlayerRspNative(byte statusCode, byte[] address);
private native boolean getMediaPlayerListRspNative(byte statusCode, int uidCounter,
- int itemCount, byte[] folderItems, int[] folderItemLengths);
+ int itemCount, byte[] folderItems, int[]
+ folderItemLengths, byte[] address);
private native boolean getFolderItemsRspNative(byte statusCode, long numItems,
int[] itemType, long[] uid, int[] type, byte[] playable, String[] displayName,
- byte[] numAtt, String[] attValues, int[] attIds);
- private native boolean getListPlayerappAttrRspNative(byte attr, byte[] attrIds);
- private native boolean getPlayerAppValueRspNative(byte numberattr, byte[]values );
- private native boolean SendCurrentPlayerValueRspNative(byte numberattr, byte[]attr );
- private native boolean SendSetPlayerAppRspNative(int attr_status);
+ byte[] numAtt, String[] attValues, int[] attIds, byte[] address);
+ private native boolean getListPlayerappAttrRspNative(byte attr,
+ byte[] attrIds, byte[] address);
+ private native boolean getPlayerAppValueRspNative(byte numberattr,
+ byte[]values, byte[] address );
+ private native boolean SendCurrentPlayerValueRspNative(byte numberattr,
+ byte[]attr, byte[] address );
+ private native boolean SendSetPlayerAppRspNative(int attr_status, byte[] address);
private native boolean sendSettingsTextRspNative(int num_attr, byte[] attr,
- int length, String[]text);
+ int length, String[]text, byte[] address);
private native boolean sendValueTextRspNative(int num_attr, byte[] attr,
- int length, String[]text);
+ int length, String[]text, byte[] address);
private native boolean registerNotificationPlayerAppRspNative(int type,
- byte numberattr, byte[]attr);
+ byte numberattr, byte[]attr, byte[] address);
private native boolean setBrowsedPlayerRspNative(byte statusCode, int uidCounter,
- int itemCount, int folderDepth, int charId, String[] folderItems);
- private native boolean changePathRspNative(int status, long itemCount);
- private native boolean playItemRspNative(int status);
+ int itemCount, int folderDepth, int charId, String[] folderItems,
+ byte[] address);
+ private native boolean changePathRspNative(int status, long itemCount, byte[] address);
+ private native boolean playItemRspNative(int status, byte[] address);
private native boolean getItemAttrRspNative(byte numAttr, int[] attrIds,
- String[] textArray);
+ String[] textArray, byte[] address);
+ private native boolean isDeviceActiveInHandOffNative(byte[] address);
/**
* A class to encapsulate all the information about a media player.
@@ -4000,33 +5179,6 @@ public final class Avrcp {
return mPlayerPackageName;
}
- public Metadata GetMetadata() {
- return mMetadata;
- }
-
- public void SetMetadata(Metadata metaData) {
- mMetadata.albumTitle = metaData.albumTitle;
- mMetadata.artist = metaData.artist;
- mMetadata.trackTitle = metaData.trackTitle;
- mMetadata.genre = metaData.genre;
- mMetadata.tracknum = metaData.tracknum;
- }
- public byte GetPlayState() {
- return mPlayState;
- }
-
- public void SetPlayState(byte playState) {
- mPlayState = playState;
- }
-
- public long GetTrackNumber() {
- return mTrackNumber;
- }
-
- public void SetTrackNumber(long trackNumber) {
- mTrackNumber = trackNumber;
- }
-
public void SetPlayerAvailablility(boolean isAvailable) {
mIsAvailable = isAvailable;
}
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 2f33522b7..7357dff5d 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -94,6 +94,7 @@ public class AdapterService extends Service {
private static final String delayConnectTimeoutDevice[] = {"00:23:3D"}; // volkswagen carkit
//For Debugging only
private static int sRefCount=0;
+ private static int mScanmode;
private int mStackReportedState;
private int mTxTimeTotalMs;
@@ -206,6 +207,7 @@ public class AdapterService extends Service {
if (TRACE_REF) {
synchronized (AdapterService.class) {
sRefCount++;
+ mScanmode = BluetoothAdapter.SCAN_MODE_CONNECTABLE;
debugLog("AdapterService() - REFCOUNT: CREATED. INSTANCE_COUNT" + sRefCount);
}
}
@@ -902,9 +904,22 @@ public class AdapterService extends Service {
return false;
}
+ //do not allow setmode when multicast is active
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(null)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore setmode " + mode);
+ mScanmode = mode;
+ return false;
+ }
+
AdapterService service = getService();
if (service == null) return false;
- return service.setScanMode(mode,duration);
+ // when scan mode is not changed during multicast, reset it last to
+ // scan mode, as we will set mode to none for multicast
+ mScanmode = service.getScanMode();
+ Log.i(TAG,"setScanMode: prev mode: " + mScanmode + " new mode: " + mode);
+ return service.setScanMode(mode, duration);
}
public int getDiscoverableTimeout() {
@@ -1466,7 +1481,6 @@ public class AdapterService extends Service {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
setDiscoverableTimeout(duration);
-
int newMode = convertScanModeToHal(mode);
return mAdapterProperties.setScanMode(newMode);
}
@@ -1486,6 +1500,13 @@ public class AdapterService extends Service {
boolean startDiscovery() {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH ADMIN permission");
+ //do not allow new connections with active multicast
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(null)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore discovery");
+ return false;
+ }
return startDiscoveryNative();
}
@@ -1536,6 +1557,13 @@ public class AdapterService extends Service {
if (deviceProp != null && deviceProp.getBondState() != BluetoothDevice.BOND_NONE) {
return false;
}
+ // Multicast: Do not allow bonding while multcast
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(null)) {
+ Log.i(TAG,"A2dp Multicast is ongoing, ignore bonding");
+ return false;
+ }
// Pairing is unreliable while scanning, so cancel discovery
// Note, remove this when native stack improves
@@ -1702,29 +1730,48 @@ public class AdapterService extends Service {
// This change makes sure that we try to re-connect
// the profile if its connection failed and priority
// for desired profile is ON.
- Log.i(TAG, "HF connected for device : " + device + " " + hfConnDevList.contains(device));
- Log.i(TAG, "A2DP connected for device : " + device + " " + a2dpConnDevList.contains(device));
+ Log.i(TAG," is HF connected" + hfConnDevList.contains(device));
+ Log.i(TAG,"is a2dp connected" + a2dpConnDevList.contains(device));
if((hfConnDevList.isEmpty() || !(hfConnDevList.contains(device))) &&
(hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) &&
(a2dpConnected || (a2dpService.getPriority(device) == BluetoothProfile.PRIORITY_OFF))) {
+ int maxConnections = 1;
+ int maxHfpConnectionSysProp =
+ SystemProperties.getInt("persist.bt.max.hs.connections", 1);
+ if (maxHfpConnectionSysProp == 2)
+ maxConnections = maxHfpConnectionSysProp;
+
+ if (!hfConnDevList.isEmpty() && maxConnections == 1) {
+ Log.v(TAG,"HFP is already connected, ignore");
+ return;
+ }
// proceed connection only if a2dp is connected to this device
// add here as if is already overloaded
- if (a2dpConnDevList.contains(device) ||
- (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)) {
+ if (a2dpConnDevList.contains(device) ||
+ (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)) {
hsService.connect(device);
} else {
- Log.d(TAG, "do not initiate connect as A2dp is not connected");
+ Log.v(TAG,"do not initiate connect as A2dp is not connected");
}
}
- else if((a2dpConnDevList.isEmpty()) &&
+ else if((a2dpConnDevList.isEmpty() || !(a2dpConnDevList.contains(device))) &&
(a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) &&
(hsConnected || (hsService.getPriority(device) == BluetoothProfile.PRIORITY_OFF))) {
-
+ int maxConnections = 1;
+ int maxA2dpConnectionSysProp =
+ SystemProperties.getInt("persist.bt.max.a2dp.connections", 1);
+ if (maxA2dpConnectionSysProp == 2)
+ maxConnections = maxA2dpConnectionSysProp;
+
+ if (!a2dpConnDevList.isEmpty() && maxConnections == 1) {
+ Log.v(TAG,"a2dp is already connected, ignore");
+ return;
+ }
// proceed connection only if HFP is connected to this device
// add here as if is already overloaded
if (hfConnDevList.contains(device) ||
- (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)) {
+ (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON)) {
a2dpService.connect(device);
} else {
Log.v(TAG,"do not initiate connect as HFP is not connected");
@@ -1774,9 +1821,9 @@ public class AdapterService extends Service {
}
else if (profileId == BluetoothProfile.A2DP) {
A2dpService a2dpService = A2dpService.getA2dpService();
+ List<BluetoothDevice> deviceList = a2dpService.getConnectedDevices();
if ((a2dpService != null) &&
(BluetoothProfile.PRIORITY_AUTO_CONNECT != a2dpService.getPriority(device))){
- List<BluetoothDevice> deviceList = a2dpService.getConnectedDevices();
adjustOtherSinkPriorities(a2dpService, deviceList);
a2dpService.setPriority(device,BluetoothProfile.PRIORITY_AUTO_CONNECT);
}
@@ -2303,6 +2350,13 @@ public class AdapterService extends Service {
dumpNative(fd);
}
+ // do not use this API.It is called only from A2spstatemachine for
+ // restoring SCAN mode after multicast is stopped
+ public boolean restoreScanMode() {
+ Log.i(TAG, "restoreScanMode: " + mScanmode);
+ return setScanMode(mScanmode, getDiscoverableTimeout());
+ }
+
private void debugLog(String msg) {
if (DBG) Log.d(TAG, msg);
}
diff --git a/src/com/android/bluetooth/gatt/GattService.java b/src/com/android/bluetooth/gatt/GattService.java
index 91dcb0e62..076822216 100644
--- a/src/com/android/bluetooth/gatt/GattService.java
+++ b/src/com/android/bluetooth/gatt/GattService.java
@@ -46,6 +46,7 @@ import android.util.Log;
import com.android.bluetooth.R;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.util.NumberUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -346,6 +347,15 @@ public class GattService extends ProfileService {
public void clientConnect(int clientIf, String address, boolean isDirect, int transport) {
GattService service = getService();
if (service == null) return;
+
+ //do not allow new connections with active multicast
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(null)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore Connection Request");
+ return;
+ }
+
service.clientConnect(clientIf, address, isDirect, transport);
}
@@ -475,6 +485,15 @@ public class GattService extends ProfileService {
public void serverConnect(int serverIf, String address, boolean isDirect, int transport) {
GattService service = getService();
if (service == null) return;
+
+ //do not allow new connections with active multicast
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(null)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore Connection Request");
+ return;
+ }
+
service.serverConnect(serverIf, address, isDirect, transport);
}
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index af4124b28..8e7c8c984 100755
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -31,6 +31,7 @@ import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
+import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.Utils;
import java.util.ArrayList;
@@ -71,6 +72,7 @@ public class HeadsetService extends ProfileService {
} catch (Exception e) {
Log.w(TAG,"Unable to register headset receiver",e);
}
+
setHeadsetService(this);
return true;
}
@@ -351,6 +353,14 @@ public class HeadsetService extends ProfileService {
return false;
}
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ //do not allow new connections with active multicast
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(device)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore Connection Request");
+ return false;
+ }
+
int connectionState = mStateMachine.getConnectionState(device);
Log.d(TAG,"connectionState = " + connectionState);
if (connectionState == BluetoothProfile.STATE_CONNECTED ||
diff --git a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index 9da73c313..7fc504111 100755
--- a/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -120,6 +120,8 @@ final class HeadsetStateMachine extends StateMachine {
private static final int CLCC_RSP_TIMEOUT = 104;
private static final int CONNECT_TIMEOUT = 201;
+ /* Allow time for possible LMP response timeout + Page timeout */
+ private static final int CONNECT_TIMEOUT_SEC = 38000;
private static final int DIALING_OUT_TIMEOUT_VALUE = 10000;
private static final int START_VR_TIMEOUT_VALUE = 5000;
@@ -375,7 +377,36 @@ final class HeadsetStateMachine extends StateMachine {
int RetryConn = mRetryConnect.get(device);
log("RetryConn = " + RetryConn);
- if (RetryConn > 1) {
+ if (RetryConn < 2) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+
+ if (!connectHfpNative(getByteAddress(device)) ) {
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ break;
+ }
+ RetryConn = RetryConn + 1;
+ mRetryConnect.put(device, RetryConn);
+ if (mPhoneProxy != null) {
+ try {
+ log("Query the phonestates");
+ mPhoneProxy.queryPhoneState();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ } else Log.e(TAG, "Phone proxy null for query phone state");
+ synchronized (HeadsetStateMachine.this) {
+ mTargetDevice = device;
+ transitionTo(mPending);
+ }
+ // TODO(BT) remove CONNECT_TIMEOUT when the stack
+ // sends back events consistently
+ Message m = obtainMessage(CONNECT_TIMEOUT);
+ m.obj = device;
+ sendMessageDelayed(m, CONNECT_TIMEOUT_SEC);
+ } else {
if (mRetryConnect.containsKey(device)) {
Log.d(TAG, "Removing device " + device +
" conn retry entry since RetryConn = " + RetryConn);
@@ -856,8 +887,60 @@ final class HeadsetStateMachine extends StateMachine {
}
int RetryConn = mRetryConnect.get(device);
- log("RetryConn = " + RetryConn);
- if (RetryConn > 1) {
+ Log.d(TAG, "RetryConn = " + RetryConn);
+ if (RetryConn < 2) {
+ if (mConnectedDevicesList.size() >= max_hf_connections) {
+ BluetoothDevice DisconnectConnectedDevice = null;
+ IState CurrentAudioState = getCurrentState();
+ Log.d(TAG, "Reach to max size, disconnect one of them first");
+ /* TODO: Disconnect based on CoD */
+ DisconnectConnectedDevice = mConnectedDevicesList.get(0);
+
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+
+ if (!disconnectHfpNative(getByteAddress(DisconnectConnectedDevice))) {
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ break;
+ } else {
+ broadcastConnectionState(DisconnectConnectedDevice,
+ BluetoothProfile.STATE_DISCONNECTING,
+ BluetoothProfile.STATE_CONNECTED);
+ }
+
+ synchronized (HeadsetStateMachine.this) {
+ mTargetDevice = device;
+ if (max_hf_connections == 1) {
+ transitionTo(mPending);
+ } else {
+ mMultiDisconnectDevice = DisconnectConnectedDevice;
+ transitionTo(mMultiHFPending);
+ }
+ DisconnectConnectedDevice = null;
+ }
+ } else if (mConnectedDevicesList.size() < max_hf_connections) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+ if (!connectHfpNative(getByteAddress(device))) {
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ break;
+ }
+ synchronized (HeadsetStateMachine.this) {
+ mTargetDevice = device;
+ // Transtion to MultiHFPending state for Multi HF connection
+ transitionTo(mMultiHFPending);
+ }
+ }
+ RetryConn = RetryConn + 1;
+ mRetryConnect.put(device, RetryConn);
+ Message m = obtainMessage(CONNECT_TIMEOUT);
+ m.obj = device;
+ sendMessageDelayed(m, CONNECT_TIMEOUT_SEC);
+ } else {
if (mRetryConnect.containsKey(device)) {
Log.d(TAG, "Removing device " + device +
" conn retry entry since RetryConn = " + RetryConn);
@@ -1321,8 +1404,60 @@ final class HeadsetStateMachine extends StateMachine {
}
int RetryConn = mRetryConnect.get(device);
- log("RetryConn = " + RetryConn);
- if (RetryConn > 1) {
+ Log.d(TAG, "RetryConn = " + RetryConn);
+ if (RetryConn < 2) {
+ if (mConnectedDevicesList.size() >= max_hf_connections) {
+ BluetoothDevice DisconnectConnectedDevice = null;
+ IState CurrentAudioState = getCurrentState();
+ Log.d(TAG, "Reach to max size, disconnect " +
+ "one of them first");
+ DisconnectConnectedDevice = mConnectedDevicesList.get(0);
+
+ if (mActiveScoDevice.equals(DisconnectConnectedDevice)) {
+ DisconnectConnectedDevice = mConnectedDevicesList.get(1);
+ }
+
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+
+ if (!disconnectHfpNative(getByteAddress(DisconnectConnectedDevice))) {
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ break;
+ } else {
+ broadcastConnectionState(DisconnectConnectedDevice,
+ BluetoothProfile.STATE_DISCONNECTING,
+ BluetoothProfile.STATE_CONNECTED);
+ }
+
+ synchronized (HeadsetStateMachine.this) {
+ mTargetDevice = device;
+ mMultiDisconnectDevice = DisconnectConnectedDevice;
+ transitionTo(mMultiHFPending);
+ DisconnectConnectedDevice = null;
+ }
+ } else if(mConnectedDevicesList.size() < max_hf_connections) {
+ broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,
+ BluetoothProfile.STATE_DISCONNECTED);
+ if (!connectHfpNative(getByteAddress(device))) {
+ broadcastConnectionState(device,
+ BluetoothProfile.STATE_DISCONNECTED,
+ BluetoothProfile.STATE_CONNECTING);
+ break;
+ }
+ synchronized (HeadsetStateMachine.this) {
+ mTargetDevice = device;
+ // Transtion to MultilHFPending state for Multi handsfree connection
+ transitionTo(mMultiHFPending);
+ }
+ }
+ RetryConn = RetryConn + 1;
+ mRetryConnect.put(device, RetryConn);
+ Message m = obtainMessage(CONNECT_TIMEOUT);
+ m.obj = device;
+ sendMessageDelayed(m, CONNECT_TIMEOUT_SEC);
+ } else {
if (mRetryConnect.containsKey(device)) {
Log.d(TAG, "Removing device " + device +
" conn retry entry since RetryConn = " + RetryConn);
@@ -1998,6 +2133,7 @@ final class HeadsetStateMachine extends StateMachine {
mConnectedDevicesList.remove(device);
mHeadsetAudioParam.remove(device);
mHeadsetBrsf.remove(device);
+
Log.d(TAG, "device " + device.getAddress() +
" is removed in MultiHFPending state");
}
diff --git a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
index d7eb12d91..b14ffb5b5 100644
--- a/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
+++ b/src/com/android/bluetooth/hfpclient/HeadsetClientService.java
@@ -31,6 +31,7 @@ import android.os.Bundle;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
+import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.Utils;
import java.util.ArrayList;
@@ -444,6 +445,14 @@ public class HeadsetClientService extends ProfileService {
return false;
}
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ //do not allow new connections with active multicast
+ if (a2dpService != null &&
+ (a2dpService.isMulticastOngoing(device))) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore Connection Request");
+ return false;
+ }
+
int connectionState = mStateMachine.getConnectionState(device);
if (connectionState == BluetoothProfile.STATE_CONNECTED ||
connectionState == BluetoothProfile.STATE_CONNECTING) {
diff --git a/src/com/android/bluetooth/hid/HidService.java b/src/com/android/bluetooth/hid/HidService.java
index 551f683e3..ba6ca2ca4 100644
--- a/src/com/android/bluetooth/hid/HidService.java
+++ b/src/com/android/bluetooth/hid/HidService.java
@@ -31,6 +31,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
import android.util.Log;
+import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.Utils;
@@ -441,6 +442,15 @@ public class HidService extends ProfileService {
//APIs
boolean connect(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ //do not allow new connections with active multicast
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(device)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore Connection Request");
+ return false;
+ }
+
if (getConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED) {
Log.e(TAG, "Hid Device not disconnected: " + device);
return false;
diff --git a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
index 3f63f48f0..1dd7fd730 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppTransfer.java
@@ -58,6 +58,8 @@ import android.os.Process;
import android.util.Log;
import com.android.bluetooth.OolConnManager;
+import com.android.bluetooth.a2dp.A2dpService;
+
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -730,6 +732,15 @@ public class BluetoothOppTransfer implements BluetoothOppBatch.BluetoothOppBatch
}
} else {
+
+ //do not allow new connections with active multicast
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(device)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore OPP send");
+ return ;
+ }
+
/* Use BluetoothSocket to connect */
l2cChannel = 0;
try {
diff --git a/src/com/android/bluetooth/pan/PanService.java b/src/com/android/bluetooth/pan/PanService.java
index f9226e6e2..e1250ca13 100755..100644
--- a/src/com/android/bluetooth/pan/PanService.java
+++ b/src/com/android/bluetooth/pan/PanService.java
@@ -41,6 +41,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
+import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.Utils;
@@ -265,6 +266,14 @@ public class PanService extends ProfileService {
boolean connect(BluetoothDevice device) {
enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ A2dpService a2dpService = A2dpService.getA2dpService();
+ //do not allow new connections with active multicast
+ if (a2dpService != null &&
+ a2dpService.isMulticastOngoing(device)) {
+ Log.i(TAG,"A2dp Multicast is Ongoing, ignore Connection Request");
+ return false;
+ }
+
if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) {
Log.e(TAG, "Pan Device not disconnected: " + device);
return false;