Merge "Treat the buffering state as playing" into pi-dev
diff --git a/android/app/jni/com_android_bluetooth_avrcp.cpp b/android/app/jni/com_android_bluetooth_avrcp.cpp
index f0d829d..1eb3553 100644
--- a/android/app/jni/com_android_bluetooth_avrcp.cpp
+++ b/android/app/jni/com_android_bluetooth_avrcp.cpp
@@ -58,7 +58,7 @@
static void cleanup_items(btrc_folder_items_t* p_items, int numItems);
-static void btavrcp_remote_features_callback(RawAddress* bd_addr,
+static void btavrcp_remote_features_callback(const RawAddress& bd_addr,
btrc_remote_features_t features) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -76,13 +76,13 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr.get(),
(jint)features);
}
/** Callback for play status request */
-static void btavrcp_get_play_status_callback(RawAddress* bd_addr) {
+static void btavrcp_get_play_status_callback(const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -99,13 +99,13 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus, addr.get());
}
static void btavrcp_get_element_attr_callback(uint8_t num_attr,
btrc_media_attr_t* p_attrs,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -131,14 +131,14 @@
sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs);
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, addr.get(),
(jbyte)num_attr, attrs.get());
}
static void btavrcp_register_notification_callback(btrc_event_id_t event_id,
uint32_t param,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -155,13 +155,13 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
addr.get(), (jint)event_id, (jint)param);
}
static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -178,14 +178,14 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback,
addr.get(), (jint)volume, (jint)ctype);
}
static void btavrcp_passthrough_command_callback(int id, int pressed,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -201,14 +201,14 @@
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd,
addr.get(), (jint)id, (jint)pressed);
}
static void btavrcp_set_addressed_player_callback(uint16_t player_id,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -225,13 +225,13 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setAddressedPlayerCallback,
addr.get(), (jint)player_id);
}
static void btavrcp_set_browsed_player_callback(uint16_t player_id,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
if (!mCallbacksObj) {
@@ -246,7 +246,7 @@
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setBrowsedPlayerCallback,
addr.get(), (jint)player_id);
@@ -254,7 +254,7 @@
static void btavrcp_get_folder_items_callback(
uint8_t scope, uint32_t start_item, uint32_t end_item, uint8_t num_attr,
- uint32_t* p_attr_ids, RawAddress* bd_addr) {
+ uint32_t* p_attr_ids, const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -273,7 +273,7 @@
uint32_t* puiAttr = (uint32_t*)p_attr_ids;
ScopedLocalRef<jintArray> attr_ids(sCallbackEnv.get(), NULL);
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
/* check number of attributes requested by remote device */
if ((num_attr != BTRC_NUM_ATTR_ALL) && (num_attr != BTRC_NUM_ATTR_NONE)) {
@@ -294,7 +294,7 @@
}
static void btavrcp_change_path_callback(uint8_t direction, uint8_t* folder_uid,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -318,7 +318,7 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->SetByteArrayRegion(
attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)folder_uid);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_changePathCallback,
@@ -329,7 +329,7 @@
uint16_t uid_counter,
uint8_t num_attr,
btrc_media_attr_t* p_attrs,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -360,7 +360,7 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs);
sCallbackEnv->SetByteArrayRegion(
attr_uid.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
@@ -371,7 +371,8 @@
}
static void btavrcp_play_item_callback(uint8_t scope, uint16_t uid_counter,
- uint8_t* uid, RawAddress* bd_addr) {
+ uint8_t* uid,
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
if (!mCallbacksObj) {
@@ -394,7 +395,7 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->SetByteArrayRegion(
attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_playItemCallback,
@@ -403,7 +404,7 @@
}
static void btavrcp_get_total_num_items_callback(uint8_t scope,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
if (!mCallbacksObj) {
@@ -419,13 +420,13 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getTotalNumOfItemsCallback,
addr.get(), (jbyte)scope);
}
static void btavrcp_search_callback(uint16_t charset_id, uint16_t str_len,
- uint8_t* p_str, RawAddress* bd_addr) {
+ uint8_t* p_str, const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
if (!mCallbacksObj) {
@@ -448,7 +449,7 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->SetByteArrayRegion(attrs.get(), 0, str_len * sizeof(uint8_t),
(jbyte*)p_str);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_searchCallback, addr.get(),
@@ -457,7 +458,7 @@
static void btavrcp_add_to_play_list_callback(uint8_t scope, uint8_t* uid,
uint16_t uid_counter,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
if (!mCallbacksObj) {
@@ -480,7 +481,7 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->SetByteArrayRegion(
attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_addToPlayListCallback,
@@ -629,9 +630,11 @@
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
bt_status_t status = sBluetoothAvrcpInterface->get_play_status_rsp(
- (RawAddress*)addr, (btrc_play_status_t)playStatus, songLen, songPos);
+ rawAddress, (btrc_play_status_t)playStatus, songLen, songPos);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed get_play_status_rsp, status: %d", status);
}
@@ -693,9 +696,10 @@
return JNI_FALSE;
}
- RawAddress* btAddr = (RawAddress*)addr;
- bt_status_t status =
- sBluetoothAvrcpInterface->get_element_attr_rsp(btAddr, numAttr, pAttrs);
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
+ bt_status_t status = sBluetoothAvrcpInterface->get_element_attr_rsp(
+ rawAddress, numAttr, pAttrs);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed get_element_attr_rsp, status: %d", status);
}
@@ -756,10 +760,11 @@
break;
}
}
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
- RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->get_item_attr_rsp(
- btAddr, (btrc_status_t)rspStatus, numAttr, pAttrs);
+ rawAddress, (btrc_status_t)rspStatus, numAttr, pAttrs);
if (status != BT_STATUS_SUCCESS)
ALOGE("Failed get_item_attr_rsp, status: %d", status);
@@ -1025,7 +1030,7 @@
RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(
- btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
+ *btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed get_folder_items_list_rsp, status: %d", status);
}
@@ -1160,7 +1165,7 @@
RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(
- btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
+ *btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
if (status != BT_STATUS_SUCCESS)
ALOGE("Failed get_folder_items_list_rsp, status: %d", status);
@@ -1198,7 +1203,7 @@
RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_rsp(
- btAddr, (btrc_status_t)rspStatus);
+ *btAddr, (btrc_status_t)rspStatus);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed set_addressed_player_rsp, status: %d", status);
}
@@ -1252,7 +1257,7 @@
uint16_t charset_id = BTRC_CHARSET_ID_UTF8;
RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_rsp(
- btAddr, (btrc_status_t)rspStatus, numItems, charset_id, folder_depth,
+ *btAddr, (btrc_status_t)rspStatus, numItems, charset_id, folder_depth,
p_folders);
if (status != BT_STATUS_SUCCESS) {
ALOGE("%s: Failed set_browsed_player_rsp, status: %d", __func__, status);
@@ -1283,7 +1288,7 @@
uint32_t nItems = (uint32_t)numItems;
RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->change_path_rsp(
- btAddr, (btrc_status_t)rspStatus, (uint32_t)nItems);
+ *btAddr, (btrc_status_t)rspStatus, (uint32_t)nItems);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed change_path_rsp, status: %d", status);
}
@@ -1309,7 +1314,8 @@
uint32_t nItems = (uint32_t)numItems;
RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->search_rsp(
- btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter, (uint32_t)nItems);
+ *btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter,
+ (uint32_t)nItems);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed search_rsp, status: %d", status);
}
@@ -1333,8 +1339,8 @@
}
RawAddress* btAddr = (RawAddress*)addr;
- bt_status_t status =
- sBluetoothAvrcpInterface->play_item_rsp(btAddr, (btrc_status_t)rspStatus);
+ bt_status_t status = sBluetoothAvrcpInterface->play_item_rsp(
+ *btAddr, (btrc_status_t)rspStatus);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed play_item_rsp, status: %d", status);
}
@@ -1360,7 +1366,8 @@
uint32_t nItems = (uint32_t)numItems;
RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->get_total_num_of_items_rsp(
- btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter, (uint32_t)nItems);
+ *btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter,
+ (uint32_t)nItems);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed get_total_num_of_items_rsp, status: %d", status);
}
@@ -1384,7 +1391,7 @@
RawAddress* btAddr = (RawAddress*)addr;
bt_status_t status = sBluetoothAvrcpInterface->add_to_now_playing_rsp(
- btAddr, (btrc_status_t)rspStatus);
+ *btAddr, (btrc_status_t)rspStatus);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed add_to_now_playing_rsp, status: %d", status);
}
diff --git a/android/app/jni/com_android_bluetooth_avrcp_controller.cpp b/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
index 86932d3..7710a91 100644
--- a/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
+++ b/android/app/jni/com_android_bluetooth_avrcp_controller.cpp
@@ -53,8 +53,8 @@
static const btrc_ctrl_interface_t* sBluetoothAvrcpInterface = NULL;
static jobject sCallbacksObj = NULL;
-static void btavrcp_passthrough_response_callback(RawAddress* bd_addr, int id,
- int pressed) {
+static void btavrcp_passthrough_response_callback(const RawAddress& bd_addr,
+ int id, int pressed) {
ALOGI("%s: id: %d, pressed: %d", __func__, id, pressed);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -67,7 +67,7 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handlePassthroughRsp,
(jint)id, (jint)pressed, addr.get());
}
@@ -82,7 +82,7 @@
}
static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect,
- RawAddress* bd_addr) {
+ const RawAddress& bd_addr) {
ALOGI("%s: conn state: rc: %d br: %d", __func__, rc_connect, br_connect);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -95,13 +95,14 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)bd_addr.address);
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_onConnectionStateChanged,
(jboolean)rc_connect, (jboolean)br_connect,
addr.get());
}
-static void btavrcp_get_rcfeatures_callback(RawAddress* bd_addr, int features) {
+static void btavrcp_get_rcfeatures_callback(const RawAddress& bd_addr,
+ int features) {
ALOGV("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -114,13 +115,13 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_getRcFeatures, addr.get(),
(jint)features);
}
static void btavrcp_setplayerapplicationsetting_rsp_callback(
- RawAddress* bd_addr, uint8_t accepted) {
+ const RawAddress& bd_addr, uint8_t accepted) {
ALOGV("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -133,14 +134,15 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_setplayerappsettingrsp,
addr.get(), (jint)accepted);
}
static void btavrcp_playerapplicationsetting_callback(
- RawAddress* bd_addr, uint8_t num_attr, btrc_player_app_attr_t* app_attrs,
- uint8_t num_ext_attr, btrc_player_app_ext_attr_t* ext_attrs) {
+ const RawAddress& bd_addr, uint8_t num_attr,
+ btrc_player_app_attr_t* app_attrs, uint8_t num_ext_attr,
+ btrc_player_app_ext_attr_t* ext_attrs) {
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -152,7 +154,7 @@
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
/* TODO ext attrs
* Flattening defined attributes: <id,num_values,values[]>
*/
@@ -187,7 +189,7 @@
}
static void btavrcp_playerapplicationsetting_changed_callback(
- RawAddress* bd_addr, btrc_player_settings_t* p_vals) {
+ const RawAddress& bd_addr, const btrc_player_settings_t& vals) {
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -199,9 +201,9 @@
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
- int arraylen = p_vals->num_attr * 2;
+ int arraylen = vals.num_attr * 2;
ScopedLocalRef<jbyteArray> playerattribs(
sCallbackEnv.get(), sCallbackEnv->NewByteArray(arraylen));
if (!playerattribs.get()) {
@@ -211,12 +213,12 @@
/*
* Flatening format: <id,val>
*/
- for (int i = 0, k = 0; (i < p_vals->num_attr) && (k < arraylen); i++) {
+ for (int i = 0, k = 0; (i < vals.num_attr) && (k < arraylen); i++) {
sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1,
- (jbyte*)&(p_vals->attr_ids[i]));
+ (jbyte*)&(vals.attr_ids[i]));
k++;
sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1,
- (jbyte*)&(p_vals->attr_values[i]));
+ (jbyte*)&(vals.attr_values[i]));
k++;
}
sCallbackEnv->CallVoidMethod(sCallbacksObj,
@@ -224,7 +226,7 @@
playerattribs.get(), (jint)arraylen);
}
-static void btavrcp_set_abs_vol_cmd_callback(RawAddress* bd_addr,
+static void btavrcp_set_abs_vol_cmd_callback(const RawAddress& bd_addr,
uint8_t abs_vol, uint8_t label) {
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
@@ -238,13 +240,13 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetAbsVolume,
addr.get(), (jbyte)abs_vol, (jbyte)label);
}
-static void btavrcp_register_notification_absvol_callback(RawAddress* bd_addr,
- uint8_t label) {
+static void btavrcp_register_notification_absvol_callback(
+ const RawAddress& bd_addr, uint8_t label) {
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -257,13 +259,13 @@
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
sCallbackEnv->CallVoidMethod(sCallbacksObj,
method_handleRegisterNotificationAbsVol,
addr.get(), (jbyte)label);
}
-static void btavrcp_track_changed_callback(RawAddress* bd_addr,
+static void btavrcp_track_changed_callback(const RawAddress& bd_addr,
uint8_t num_attr,
btrc_element_attr_val_t* p_attrs) {
/*
@@ -288,7 +290,7 @@
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
jclass strclazz = sCallbackEnv->FindClass("java/lang/String");
ScopedLocalRef<jobjectArray> stringArray(
@@ -317,7 +319,7 @@
stringArray.get());
}
-static void btavrcp_play_position_changed_callback(RawAddress* bd_addr,
+static void btavrcp_play_position_changed_callback(const RawAddress& bd_addr,
uint32_t song_len,
uint32_t song_pos) {
ALOGI("%s", __func__);
@@ -331,13 +333,13 @@
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaypositionchanged,
addr.get(), (jint)(song_len), (jint)song_pos);
}
static void btavrcp_play_status_changed_callback(
- RawAddress* bd_addr, btrc_play_status_t play_status) {
+ const RawAddress& bd_addr, btrc_play_status_t play_status) {
ALOGI("%s", __func__);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -349,13 +351,13 @@
return;
}
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
- (jbyte*)bd_addr);
+ (jbyte*)&bd_addr.address);
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaystatuschanged,
addr.get(), (jbyte)play_status);
}
static void btavrcp_get_folder_items_callback(
- RawAddress* bd_addr, btrc_status_t status,
+ const RawAddress& bd_addr, btrc_status_t status,
const btrc_folder_items_t* folder_items, uint8_t count) {
/* Folder items are list of items that can be either BTRC_ITEM_PLAYER
* BTRC_ITEM_MEDIA, BTRC_ITEM_FOLDER. Here we translate them to their java
@@ -545,7 +547,8 @@
}
}
-static void btavrcp_change_path_callback(RawAddress* bd_addr, uint32_t count) {
+static void btavrcp_change_path_callback(const RawAddress& bd_addr,
+ uint32_t count) {
ALOGI("%s count %d", __func__, count);
CallbackEnv sCallbackEnv(__func__);
if (!sCallbackEnv.valid()) return;
@@ -554,7 +557,7 @@
(jint)count);
}
-static void btavrcp_set_browsed_player_callback(RawAddress* bd_addr,
+static void btavrcp_set_browsed_player_callback(const RawAddress& bd_addr,
uint8_t num_items,
uint8_t depth) {
ALOGI("%s items %d depth %d", __func__, num_items, depth);
@@ -565,7 +568,7 @@
(jint)num_items, (jint)depth);
}
-static void btavrcp_set_addressed_player_callback(RawAddress* bd_addr,
+static void btavrcp_set_addressed_player_callback(const RawAddress& bd_addr,
uint8_t status) {
ALOGI("%s status %d", __func__, status);
@@ -738,8 +741,10 @@
return JNI_FALSE;
}
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
bt_status_t status = sBluetoothAvrcpInterface->send_pass_through_cmd(
- (RawAddress*)addr, (uint8_t)key_code, (uint8_t)key_state);
+ rawAddress, (uint8_t)key_code, (uint8_t)key_state);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending passthru command, status: %d", status);
}
@@ -763,9 +768,11 @@
jniThrowIOException(env, EINVAL);
return JNI_FALSE;
}
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
bt_status_t status = sBluetoothAvrcpInterface->send_group_navigation_cmd(
- (RawAddress*)addr, (uint8_t)key_code, (uint8_t)key_state);
+ rawAddress, (uint8_t)key_code, (uint8_t)key_state);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending Grp Navigation command, status: %d", status);
}
@@ -810,9 +817,11 @@
pAttrs[i] = (uint8_t)attr[i];
pAttrsVal[i] = (uint8_t)attr_val[i];
}
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
bt_status_t status = sBluetoothAvrcpInterface->set_player_app_setting_cmd(
- (RawAddress*)addr, (uint8_t)num_attrib, pAttrs, pAttrsVal);
+ rawAddress, (uint8_t)num_attrib, pAttrs, pAttrsVal);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending setPlAppSettValNative command, status: %d", status);
}
@@ -834,8 +843,11 @@
}
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
+
bt_status_t status = sBluetoothAvrcpInterface->set_volume_rsp(
- (RawAddress*)addr, (uint8_t)abs_vol, (uint8_t)label);
+ rawAddress, (uint8_t)abs_vol, (uint8_t)label);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending sendAbsVolRspNative command, status: %d", status);
}
@@ -853,8 +865,11 @@
return;
}
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
+
bt_status_t status = sBluetoothAvrcpInterface->register_abs_vol_rsp(
- (RawAddress*)addr, (btrc_notification_type_t)rsp_type, (uint8_t)abs_vol,
+ rawAddress, (btrc_notification_type_t)rsp_type, (uint8_t)abs_vol,
(uint8_t)label);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending sendRegisterAbsVolRspNative command, status: %d",
@@ -873,8 +888,11 @@
return;
}
ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
+
bt_status_t status =
- sBluetoothAvrcpInterface->get_playback_state_cmd((RawAddress*)addr);
+ sBluetoothAvrcpInterface->get_playback_state_cmd(rawAddress);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending getPlaybackStateNative command, status: %d", status);
}
@@ -890,8 +908,11 @@
return;
}
ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
+
bt_status_t status = sBluetoothAvrcpInterface->get_now_playing_list_cmd(
- (RawAddress*)addr, start, end);
+ rawAddress, start, end);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending getNowPlayingListNative command, status: %d", status);
}
@@ -907,8 +928,11 @@
return;
}
ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
- bt_status_t status = sBluetoothAvrcpInterface->get_folder_list_cmd(
- (RawAddress*)addr, start, end);
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
+
+ bt_status_t status =
+ sBluetoothAvrcpInterface->get_folder_list_cmd(rawAddress, start, end);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending getFolderListNative command, status: %d", status);
}
@@ -924,9 +948,11 @@
return;
}
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
- bt_status_t status = sBluetoothAvrcpInterface->get_player_list_cmd(
- (RawAddress*)addr, start, end);
+ bt_status_t status =
+ sBluetoothAvrcpInterface->get_player_list_cmd(rawAddress, start, end);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending getPlayerListNative command, status: %d", status);
}
@@ -950,9 +976,11 @@
}
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
bt_status_t status = sBluetoothAvrcpInterface->change_folder_path_cmd(
- (RawAddress*)addr, (uint8_t)direction, (uint8_t*)uid);
+ rawAddress, (uint8_t)direction, (uint8_t*)uid);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending changeFolderPathNative command, status: %d", status);
}
@@ -967,10 +995,12 @@
jniThrowIOException(env, EINVAL);
return;
}
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_cmd(
- (RawAddress*)addr, (uint16_t)id);
+ rawAddress, (uint16_t)id);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending setBrowsedPlayerNative command, status: %d", status);
}
@@ -985,10 +1015,12 @@
jniThrowIOException(env, EINVAL);
return;
}
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_cmd(
- (RawAddress*)addr, (uint16_t)id);
+ rawAddress, (uint16_t)id);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending setAddressedPlayerNative command, status: %d",
status);
@@ -1010,10 +1042,12 @@
jniThrowIOException(env, EINVAL);
return;
}
+ RawAddress rawAddress;
+ rawAddress.FromOctets((uint8_t*)addr);
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
bt_status_t status = sBluetoothAvrcpInterface->play_item_cmd(
- (RawAddress*)addr, (uint8_t)scope, (uint8_t*)uid, (uint16_t)uidCounter);
+ rawAddress, (uint8_t)scope, (uint8_t*)uid, (uint16_t)uidCounter);
if (status != BT_STATUS_SUCCESS) {
ALOGE("Failed sending playItemNative command, status: %d", status);
}
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
index 599e5df..34c3331 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -331,12 +331,15 @@
* The check considers a number of factors during the evaluation.
*
* @param device the peer device to connect to
+ * @param isOutgoingRequest if true, the check is for outgoing connection
+ * request, otherwise is for incoming connection request
* @return true if connection is allowed, otherwise false
*/
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
- public boolean okToConnect(BluetoothDevice device) {
+ public boolean okToConnect(BluetoothDevice device, boolean isOutgoingRequest) {
+ Log.i(TAG, "okToConnect: device " + device + " isOutgoingRequest: " + isOutgoingRequest);
// Check if this is an incoming connection in Quiet mode.
- if (mAdapterService.isQuietModeEnabled()) {
+ if (mAdapterService.isQuietModeEnabled() && !isOutgoingRequest) {
Log.e(TAG, "okToConnect: cannot connect to " + device + " : quiet mode enabled");
return false;
}
@@ -435,6 +438,11 @@
if (DBG) {
Log.d(TAG, "setActiveDevice(" + device + "): previous is " + previousActiveDevice);
}
+
+ if (previousActiveDevice != null && AvrcpTargetService.get() != null) {
+ AvrcpTargetService.get().storeVolumeForDevice(previousActiveDevice);
+ }
+
if (device == null) {
// Clear the active device
mActiveDevice = null;
@@ -452,7 +460,7 @@
previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
BluetoothProfile.A2DP,
getConnectionState(previousActiveDevice)
- == BluetoothProfile.STATE_CONNECTED);
+ == BluetoothProfile.STATE_CONNECTED, -1);
// Make sure the Active device in native layer is set to null and audio is off
if (!mA2dpNativeInterface.setActiveDevice(null)) {
Log.w(TAG, "setActiveDevice(null): Cannot remove active device in native "
@@ -495,11 +503,21 @@
if (previousActiveDevice != null) {
mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
previousActiveDevice, BluetoothProfile.STATE_DISCONNECTED,
- BluetoothProfile.A2DP, true);
+ BluetoothProfile.A2DP, true, -1);
}
+
+ int rememberedVolume = -1;
+ if (AvrcpTargetService.get() != null) {
+ AvrcpTargetService.get().volumeDeviceSwitched(mActiveDevice);
+
+ rememberedVolume = AvrcpTargetService.get()
+ .getRememberedVolumeForDevice(mActiveDevice);
+ }
+
mAudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
mActiveDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.A2DP,
- true);
+ true, rememberedVolume);
+
// Inform the Audio Service about the codec configuration
// change, so the Audio Service can reset accordingly the audio
// feeding parameters in the Audio HAL to the Bluetooth stack.
@@ -803,14 +821,6 @@
Log.d(TAG, "broadcastActiveDevice(" + device + ")");
}
- // We need to inform AVRCP that the device has switched before informing the audio service
- // so that AVRCP can prepare and wait on audio service connecting the new stream before
- // restoring the previous volume. Otherwise the updated volume could be applied to the
- // old active device before the switch has fully completed.
- if (AvrcpTargetService.get() != null) {
- AvrcpTargetService.get().volumeDeviceSwitched(device);
- }
-
Intent intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java b/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
index 26e9571..3ab26e1 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java
@@ -185,7 +185,7 @@
Log.e(TAG, "Disconnected: error connecting to " + mDevice);
break;
}
- if (mA2dpService.okToConnect(mDevice)) {
+ if (mA2dpService.okToConnect(mDevice, true)) {
transitionTo(mConnecting);
} else {
// Reject the request and stay in Disconnected state
@@ -226,7 +226,7 @@
Log.w(TAG, "Ignore A2DP DISCONNECTED event: " + mDevice);
break;
case A2dpStackEvent.CONNECTION_STATE_CONNECTING:
- if (mA2dpService.okToConnect(mDevice)) {
+ if (mA2dpService.okToConnect(mDevice, false)) {
Log.i(TAG, "Incoming A2DP Connecting request accepted: " + mDevice);
transitionTo(mConnecting);
} else {
@@ -237,7 +237,7 @@
break;
case A2dpStackEvent.CONNECTION_STATE_CONNECTED:
Log.w(TAG, "A2DP Connected from Disconnected state: " + mDevice);
- if (mA2dpService.okToConnect(mDevice)) {
+ if (mA2dpService.okToConnect(mDevice, false)) {
Log.i(TAG, "Incoming A2DP Connected request accepted: " + mDevice);
transitionTo(mConnected);
} else {
@@ -428,7 +428,7 @@
transitionTo(mDisconnected);
break;
case A2dpStackEvent.CONNECTION_STATE_CONNECTED:
- if (mA2dpService.okToConnect(mDevice)) {
+ if (mA2dpService.okToConnect(mDevice, false)) {
Log.w(TAG, "Disconnecting interrupted: device is connected: " + mDevice);
transitionTo(mConnected);
} else {
@@ -438,7 +438,7 @@
}
break;
case A2dpStackEvent.CONNECTION_STATE_CONNECTING:
- if (mA2dpService.okToConnect(mDevice)) {
+ if (mA2dpService.okToConnect(mDevice, false)) {
Log.i(TAG, "Disconnecting interrupted: try to reconnect: " + mDevice);
transitionTo(mConnecting);
} else {
diff --git a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
index caf4864..f442c49 100644
--- a/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
+++ b/android/app/src/com/android/bluetooth/a2dpsink/A2dpSinkStreamHandler.java
@@ -111,8 +111,14 @@
}
switch (message.what) {
case SRC_STR_START:
- // Audio stream has started, stop it if we don't have focus.
mStreamAvailable = true;
+ // Always request audio focus if on TV.
+ if (isTvDevice()) {
+ if (mAudioFocus == AudioManager.AUDIOFOCUS_NONE) {
+ requestAudioFocus();
+ }
+ }
+ // Audio stream has started, stop it if we don't have focus.
if (mAudioFocus == AudioManager.AUDIOFOCUS_NONE) {
sendAvrcpPause();
} else {
@@ -142,7 +148,7 @@
case SRC_PLAY:
// Remote play command.
// If is an iot device gain focus and start avrcp updates.
- if (isIotDevice()) {
+ if (isIotDevice() || isTvDevice()) {
if (mAudioFocus == AudioManager.AUDIOFOCUS_NONE) {
requestAudioFocus();
}
@@ -367,4 +373,9 @@
private boolean isIotDevice() {
return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_EMBEDDED);
}
+
+ private boolean isTvDevice() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
}
diff --git a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
index 7edf182..3077664 100644
--- a/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
+++ b/android/app/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
@@ -91,8 +91,10 @@
static final int ABS_VOL_TIMEOUT_MILLIS = 1000; //1s
static final int CMD_TIMEOUT_MILLIS = 5000; // 5s
- // Fetch only 5 items at a time.
- static final int GET_FOLDER_ITEMS_PAGINATION_SIZE = 5;
+ // Fetch only 20 items at a time.
+ static final int GET_FOLDER_ITEMS_PAGINATION_SIZE = 20;
+ // Fetch no more than 1000 items per directory.
+ static final int MAX_FOLDER_ITEMS = 1000;
/*
* Base value for absolute volume from JNI
@@ -590,7 +592,7 @@
Log.d(STATE_TAG, "startInd " + startInd + " endInd " + endInd);
}
mStartInd = startInd;
- mEndInd = endInd;
+ mEndInd = Math.min(endInd, MAX_FOLDER_ITEMS);
}
@Override
diff --git a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
index c71c0da..a0ad490 100644
--- a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -78,10 +78,10 @@
private static final int MESSAGE_PROFILE_INIT_PRIORITIES = 2;
private static final int MESSAGE_CONNECT_OTHER_PROFILES = 3;
private static final int MESSAGE_ADAPTER_STATE_TURNED_ON = 4;
+ private static final int MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED = 5;
// Timeouts
- @VisibleForTesting
- static int sConnectOtherProfilesTimeoutMillis = 6000; // 6s
+ @VisibleForTesting static int sConnectOtherProfilesTimeoutMillis = 6000; // 6s
private final AdapterService mAdapterService;
private final ServiceFactory mFactory;
@@ -110,6 +110,11 @@
BluetoothProfile.A2DP, -1, // No-op argument
intent).sendToTarget();
break;
+ case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
+ mHandler.obtainMessage(MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED,
+ BluetoothProfile.A2DP, -1, // No-op argument
+ intent).sendToTarget();
+ break;
case BluetoothAdapter.ACTION_STATE_CHANGED:
// Only pass the message on if the adapter has actually changed state from
// non-ON to ON. NOTE: ON is the state depicting BREDR ON and not just BLE ON.
@@ -169,6 +174,14 @@
}
break;
+ case MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED: {
+ Intent intent = (Intent) msg.obj;
+ BluetoothDevice activeDevice =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ processProfileActiveDeviceChanged(activeDevice, msg.arg1);
+ }
+ break;
+
case MESSAGE_CONNECT_OTHER_PROFILES: {
// Called when we try connect some profiles in processConnectOtherProfiles but
// we send a delayed message to try connecting the remaining profiles
@@ -195,6 +208,7 @@
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_UUID);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+ filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
mAdapterService.registerReceiver(mReceiver, filter);
}
@@ -246,9 +260,9 @@
panService.setPriority(device, BluetoothProfile.PRIORITY_ON);
}
- if ((hearingAidService != null)
- && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)
- && (hearingAidService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)) {
+ if ((hearingAidService != null) && BluetoothUuid.isUuidPresent(uuids,
+ BluetoothUuid.HearingAid) && (hearingAidService.getPriority(device)
+ == BluetoothProfile.PRIORITY_UNDEFINED)) {
debugLog("setting hearing aid profile priority for device " + device);
hearingAidService.setPriority(device, BluetoothProfile.PRIORITY_ON);
}
@@ -269,13 +283,46 @@
break;
}
connectOtherProfile(device);
- setProfileAutoConnectionPriority(device, profileId, true);
}
if (prevState == BluetoothProfile.STATE_CONNECTING
&& nextState == BluetoothProfile.STATE_DISCONNECTED) {
- setProfileAutoConnectionPriority(device, profileId, false);
+ HeadsetService hsService = mFactory.getHeadsetService();
+ boolean hsDisconnected = hsService == null || hsService.getConnectionState(device)
+ == BluetoothProfile.STATE_DISCONNECTED;
+ A2dpService a2dpService = mFactory.getA2dpService();
+ boolean a2dpDisconnected = a2dpService == null
+ || a2dpService.getConnectionState(device)
+ == BluetoothProfile.STATE_DISCONNECTED;
+ debugLog("processProfileStateChanged, device=" + device + ", a2dpDisconnected="
+ + a2dpDisconnected + ", hsDisconnected=" + hsDisconnected);
+ if (hsDisconnected && a2dpDisconnected) {
+ removeAutoConnectFromA2dpSink(device);
+ removeAutoConnectFromHeadset(device);
+ }
}
+ }
+ }
+ private void processProfileActiveDeviceChanged(BluetoothDevice activeDevice, int profileId) {
+ debugLog("processProfileActiveDeviceChanged, activeDevice=" + activeDevice + ", profile="
+ + profileId);
+ switch (profileId) {
+ // Tracking active device changed intent only for A2DP so that we always connect to a
+ // single device after toggling Bluetooth
+ case BluetoothProfile.A2DP:
+ // Ignore null active device since we don't know if the change is triggered by
+ // normal device disconnection during Bluetooth shutdown or user action
+ if (activeDevice == null) {
+ warnLog("processProfileActiveDeviceChanged: ignore null A2DP active device");
+ return;
+ }
+ for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
+ removeAutoConnectFromA2dpSink(device);
+ removeAutoConnectFromHeadset(device);
+ }
+ setAutoConnectForA2dpSink(activeDevice);
+ setAutoConnectForHeadset(activeDevice);
+ break;
}
}
@@ -286,67 +333,55 @@
private void autoConnect() {
if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) {
- errorLog("autoConnect() - BT is not ON. Exiting autoConnect");
+ errorLog("autoConnect: BT is not ON. Exiting autoConnect");
return;
}
if (!mAdapterService.isQuietModeEnabled()) {
- debugLog("autoConnect() - Initiate auto connection on BT on...");
- // Phone profiles.
- autoConnectHeadset();
- autoConnectA2dp();
+ debugLog("autoConnect: Initiate auto connection on BT on...");
+ final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
+ if (bondedDevices == null) {
+ errorLog("autoConnect: bondedDevices are null");
+ return;
+ }
+ for (BluetoothDevice device : bondedDevices) {
+ autoConnectHeadset(device);
+ autoConnectA2dp(device);
+ }
} else {
debugLog("autoConnect() - BT is in quiet mode. Not initiating auto connections");
}
}
- private void autoConnectHeadset() {
- final HeadsetService hsService = mFactory.getHeadsetService();
- if (hsService == null) {
- errorLog("autoConnectHeadset, service is null");
+ private void autoConnectA2dp(BluetoothDevice device) {
+ final A2dpService a2dpService = mFactory.getA2dpService();
+ if (a2dpService == null) {
+ warnLog("autoConnectA2dp: service is null, failed to connect to " + device);
return;
}
- final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
- if (bondedDevices == null) {
- errorLog("autoConnectHeadset, bondedDevices are null");
- return;
- }
- for (BluetoothDevice device : bondedDevices) {
- int priority = hsService.getPriority(device);
- debugLog("autoConnectHeadset, attempt auto-connect with device " + device
- + " priority " + priority);
- if (priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
- debugLog("autoConnectHeadset, Connecting HFP with " + device);
- hsService.connect(device);
- } else {
- debugLog("autoConnectHeadset, skipped auto-connect with device " + device
- + " priority " + priority);
- }
+ int a2dpPriority = a2dpService.getPriority(device);
+ if (a2dpPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+ debugLog("autoConnectA2dp: connecting A2DP with " + device);
+ a2dpService.connect(device);
+ } else {
+ debugLog("autoConnectA2dp: skipped auto-connect A2DP with device " + device
+ + " priority " + a2dpPriority);
}
}
- private void autoConnectA2dp() {
- final A2dpService a2dpService = mFactory.getA2dpService();
- if (a2dpService == null) {
- errorLog("autoConnectA2dp, service is null");
+ private void autoConnectHeadset(BluetoothDevice device) {
+ final HeadsetService hsService = mFactory.getHeadsetService();
+ if (hsService == null) {
+ warnLog("autoConnectHeadset: service is null, failed to connect to " + device);
return;
}
- final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
- if (bondedDevices == null) {
- errorLog("autoConnectA2dp, bondedDevices are null");
- return;
- }
- for (BluetoothDevice device : bondedDevices) {
- int priority = a2dpService.getPriority(device);
- debugLog("autoConnectA2dp, attempt auto-connect with device " + device
- + " priority " + priority);
- if (priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
- debugLog("autoConnectA2dp, connecting A2DP with " + device);
- a2dpService.connect(device);
- } else {
- debugLog("autoConnectA2dp, skipped auto-connect with device " + device
- + " priority " + priority);
- }
+ int headsetPriority = hsService.getPriority(device);
+ if (headsetPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+ debugLog("autoConnectHeadset: Connecting HFP with " + device);
+ hsService.connect(device);
+ } else {
+ debugLog("autoConnectHeadset: skipped auto-connect HFP with device " + device
+ + " priority " + headsetPriority);
}
}
@@ -444,62 +479,74 @@
}
}
- private void setProfileAutoConnectionPriority(BluetoothDevice device, int profileId,
- boolean autoConnect) {
- debugLog("setProfileAutoConnectionPriority: device=" + device + ", profile=" + profileId
- + ", autoConnect=" + autoConnect);
- switch (profileId) {
- case BluetoothProfile.HEADSET: {
- HeadsetService hsService = mFactory.getHeadsetService();
- if (hsService == null) {
- warnLog("setProfileAutoConnectionPriority: HEADSET service is null");
- break;
- }
- removeAutoConnectFromDisconnectedHeadsets(hsService);
- if (autoConnect) {
- hsService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
- }
- break;
- }
- case BluetoothProfile.A2DP: {
- A2dpService a2dpService = mFactory.getA2dpService();
- if (a2dpService == null) {
- warnLog("setProfileAutoConnectionPriority: A2DP service is null");
- break;
- }
- removeAutoConnectFromDisconnectedA2dpSinks(a2dpService);
- if (autoConnect) {
- a2dpService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
- }
- break;
- }
- default:
- Log.w(TAG, "Tried to set AutoConnect priority on invalid profile " + profileId);
- break;
+ /**
+ * Set a device's headset profile priority to PRIORITY_AUTO_CONNECT if device support that
+ * profile
+ *
+ * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT
+ */
+ private void setAutoConnectForHeadset(BluetoothDevice device) {
+ HeadsetService hsService = mFactory.getHeadsetService();
+ if (hsService == null) {
+ warnLog("setAutoConnectForHeadset: HEADSET service is null");
+ return;
+ }
+ if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) {
+ debugLog("setAutoConnectForHeadset: device " + device + " PRIORITY_AUTO_CONNECT");
+ hsService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
}
}
- private void removeAutoConnectFromDisconnectedHeadsets(HeadsetService hsService) {
- List<BluetoothDevice> connectedDeviceList = hsService.getConnectedDevices();
- for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
- if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT
- && !connectedDeviceList.contains(device)) {
- debugLog("removeAutoConnectFromDisconnectedHeadsets, device " + device
- + " PRIORITY_ON");
- hsService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
+ /**
+ * Set a device's A2DP profile priority to PRIORITY_AUTO_CONNECT if device support that profile
+ *
+ * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT
+ */
+ private void setAutoConnectForA2dpSink(BluetoothDevice device) {
+ A2dpService a2dpService = mFactory.getA2dpService();
+ if (a2dpService == null) {
+ warnLog("setAutoConnectForA2dpSink: A2DP service is null");
+ return;
+ }
+ if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) {
+ debugLog("setAutoConnectForA2dpSink: device " + device + " PRIORITY_AUTO_CONNECT");
+ a2dpService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
}
}
- private void removeAutoConnectFromDisconnectedA2dpSinks(A2dpService a2dpService) {
- List<BluetoothDevice> connectedDeviceList = a2dpService.getConnectedDevices();
- for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
- if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT
- && !connectedDeviceList.contains(device)) {
- debugLog("removeAutoConnectFromDisconnectedA2dpSinks, device " + device
- + " PRIORITY_ON");
- a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
- }
+ /**
+ * Remove PRIORITY_AUTO_CONNECT from all headsets and set headset that used to have
+ * PRIORITY_AUTO_CONNECT to PRIORITY_ON
+ *
+ * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed
+ */
+ private void removeAutoConnectFromHeadset(BluetoothDevice device) {
+ HeadsetService hsService = mFactory.getHeadsetService();
+ if (hsService == null) {
+ warnLog("removeAutoConnectFromHeadset: HEADSET service is null");
+ return;
+ }
+ if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+ debugLog("removeAutoConnectFromHeadset: device " + device + " PRIORITY_ON");
+ hsService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+ }
+ }
+
+ /**
+ * Remove PRIORITY_AUTO_CONNECT from all A2DP sinks and set A2DP sink that used to have
+ * PRIORITY_AUTO_CONNECT to PRIORITY_ON
+ *
+ * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed
+ */
+ private void removeAutoConnectFromA2dpSink(BluetoothDevice device) {
+ A2dpService a2dpService = mFactory.getA2dpService();
+ if (a2dpService == null) {
+ warnLog("removeAutoConnectFromA2dpSink: A2DP service is null");
+ return;
+ }
+ if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT) {
+ debugLog("removeAutoConnectFromA2dpSink: device " + device + " PRIORITY_ON");
+ a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
}
}
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
index 76ff7b9..db115ca 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -1499,6 +1499,13 @@
doForEachConnectedStateMachine(
stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.CALL_STATE_CHANGED,
new HeadsetCallState(numActive, numHeld, callState, number, type)));
+ mStateMachinesThread.getThreadHandler().post(() -> {
+ if (callState == HeadsetHalConstants.CALL_STATE_IDLE
+ && !shouldCallAudioBeActive() && !isAudioOn()) {
+ // Resume A2DP when call ended and SCO is not connected
+ mSystemInterface.getAudioManager().setParameters("A2dpSuspended=false");
+ }
+ });
}
diff --git a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
index 266358c..844c470 100644
--- a/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java
@@ -120,7 +120,7 @@
private static final long QUERY_CURRENT_CALLS_WAIT_MILLIS = 2 * 1000; // 2 seconds
// Keep track of audio routing across all devices.
- private static boolean sAudioIsRouted = true;
+ private static boolean sAudioIsRouted = false;
private final Disconnected mDisconnected;
private final Connecting mConnecting;
diff --git a/android/app/src/com/android/bluetooth/hid/HidDeviceService.java b/android/app/src/com/android/bluetooth/hid/HidDeviceService.java
index 8991b81..eb0de8e 100644
--- a/android/app/src/com/android/bluetooth/hid/HidDeviceService.java
+++ b/android/app/src/com/android/bluetooth/hid/HidDeviceService.java
@@ -657,6 +657,11 @@
Log.d(TAG, "stop()");
}
+ if (sHidDeviceService == null) {
+ Log.w(TAG, "stop() called before start()");
+ return true;
+ }
+
setHidDeviceService(null);
if (mNativeAvailable) {
mHidDeviceNativeInterface.cleanup();
diff --git a/android/app/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java b/android/app/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java
index 9e1e44e..6636d24 100644
--- a/android/app/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java
+++ b/android/app/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java
@@ -169,6 +169,11 @@
protected boolean stop() {
Log.i(TAG, "Stopping the AVRCP Target Service");
+ if (sInstance == null) {
+ Log.w(TAG, "stop() called before start()");
+ return true;
+ }
+
sInstance = null;
unregisterReceiver(mReceiver);
@@ -198,9 +203,9 @@
}
/**
- * Signal to the service that the current audio out device has changed. The current volume
- * for the old device is saved and the new device has its volume restored. If there is no
- * saved volume use the current system volume.
+ * Signal to the service that the current audio out device has changed and to inform
+ * the audio service whether the new device supports absolute volume. If it does, also
+ * set the absolute volume level on the remote device.
*/
public void volumeDeviceSwitched(BluetoothDevice device) {
if (DEBUG) {
@@ -209,6 +214,25 @@
mVolumeManager.volumeDeviceSwitched(device);
}
+ /**
+ * Store the current system volume for a device in order to be retrieved later.
+ */
+ public void storeVolumeForDevice(BluetoothDevice device) {
+ if (device == null) return;
+
+ mVolumeManager.storeVolumeForDevice(device);
+ }
+
+ /**
+ * Retrieve the remembered volume for a device. Returns -1 if there is no volume for the
+ * device.
+ */
+ public int getRememberedVolumeForDevice(BluetoothDevice device) {
+ if (device == null) return -1;
+
+ return mVolumeManager.getVolume(device, -1);
+ }
+
// TODO (apanicke): Add checks to blacklist Absolute Volume devices if they behave poorly.
void setVolume(int avrcpVolume) {
int deviceVolume =
diff --git a/android/app/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java b/android/app/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java
index 9652433..f1f99d2 100644
--- a/android/app/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java
+++ b/android/app/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java
@@ -22,8 +22,6 @@
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.SharedPreferences;
-import android.media.AudioDeviceCallback;
-import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.util.Log;
@@ -31,7 +29,7 @@
import java.util.Map;
import java.util.Objects;
-class AvrcpVolumeManager extends AudioDeviceCallback {
+class AvrcpVolumeManager {
public static final String TAG = "NewAvrcpVolumeManager";
public static final boolean DEBUG = true;
@@ -48,7 +46,6 @@
HashMap<BluetoothDevice, Boolean> mDeviceMap = new HashMap();
HashMap<BluetoothDevice, Integer> mVolumeMap = new HashMap();
- BluetoothDevice mDeferredDevice = null;
BluetoothDevice mCurrentDevice = null;
boolean mAbsoluteVolumeSupported = false;
@@ -67,31 +64,17 @@
return mContext.getSharedPreferences(VOLUME_MAP, Context.MODE_PRIVATE);
}
- private int getVolume(@NonNull BluetoothDevice device, int defaultValue) {
- if (!mVolumeMap.containsKey(device)) {
- Log.w(TAG, "getVolume: Couldn't find volume preference for device: " + device);
- return defaultValue;
- }
-
- return mVolumeMap.get(device);
- }
-
private void switchVolumeDevice(@NonNull BluetoothDevice device) {
// Inform the audio manager that the device has changed
+ d("switchVolumeDevice: Set Absolute volume support to " + mDeviceMap.get(device));
mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(), mDeviceMap.get(device));
// Get the current system volume and try to get the preference volume
int currVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
int savedVolume = getVolume(device, currVolume);
- // If the preference volume isn't equal to the current stream volume then that means
- // we had a stored preference.
d("switchVolumeDevice: currVolume=" + currVolume + " savedVolume=" + savedVolume);
- Log.i(TAG, "switchVolumeDevice: restoring volume level " + savedVolume);
- mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, savedVolume,
- AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME);
-
// If absolute volume for the device is supported, set the volume for the device
if (mDeviceMap.get(device)) {
int avrcpVolume = systemToAvrcpVolume(savedVolume);
@@ -100,43 +83,6 @@
}
}
- @Override
- public synchronized void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
- if (mDeferredDevice == null) {
- d("onAudioDevicesAdded: Not expecting device changed");
- return;
- }
-
- boolean foundDevice = false;
- d("onAudioDevicesAdded: size: " + addedDevices.length);
- for (int i = 0; i < addedDevices.length; i++) {
- d("onAudioDevicesAdded: address=" + addedDevices[i].getAddress());
- if (addedDevices[i].getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP
- && Objects.equals(addedDevices[i].getAddress(), mDeferredDevice.getAddress())) {
- foundDevice = true;
- break;
- }
- }
-
- if (!foundDevice) {
- d("Didn't find deferred device in list: device=" + mDeferredDevice);
- return;
- }
-
- mCurrentDevice = mDeferredDevice;
- mDeferredDevice = null;
-
- // A2DP can sometimes connect and set a device to active before AVRCP has determined if the
- // device supports absolute volume. Defer switching the device until AVRCP returns the
- // info.
- if (!mDeviceMap.containsKey(mCurrentDevice)) {
- Log.w(TAG, "volumeDeviceSwitched: Device isn't connected: " + mCurrentDevice);
- return;
- }
-
- switchVolumeDevice(mCurrentDevice);
- }
-
AvrcpVolumeManager(Context context, AudioManager audioManager,
AvrcpNativeInterface nativeInterface) {
mContext = context;
@@ -144,8 +90,6 @@
mNativeInterface = nativeInterface;
sDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
- mAudioManager.registerAudioDeviceCallback(this, null);
-
// Load the stored volume preferences into a hash map since shared preferences are slow
// to poll and update. If the device has been unbonded since last start remove it from
// the map.
@@ -166,19 +110,29 @@
volumeMapEditor.apply();
}
- void storeVolume() {
+ void storeVolumeForDevice(BluetoothDevice device) {
SharedPreferences.Editor pref = getVolumeMap().edit();
int storeVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
- Log.i(TAG, "storeVolume: Storing stream volume level for device " + mCurrentDevice
+ Log.i(TAG, "storeVolume: Storing stream volume level for device " + device
+ " : " + storeVolume);
- mVolumeMap.put(mCurrentDevice, storeVolume);
- pref.putInt(mCurrentDevice.getAddress(), storeVolume);
+ mVolumeMap.put(device, storeVolume);
+ pref.putInt(device.getAddress(), storeVolume);
// Always use apply() since it is asynchronous, otherwise the call can hang waiting for
// storage to be written.
pref.apply();
}
+ int getVolume(@NonNull BluetoothDevice device, int defaultValue) {
+ if (!mVolumeMap.containsKey(device)) {
+ Log.w(TAG, "getVolume: Couldn't find volume preference for device: " + device);
+ return defaultValue;
+ }
+
+ d("getVolume: Returning volume " + mVolumeMap.get(device));
+ return mVolumeMap.get(device);
+ }
+
synchronized void deviceConnected(@NonNull BluetoothDevice device, boolean absoluteVolume) {
d("deviceConnected: device=" + device + " absoluteVolume=" + absoluteVolume);
@@ -198,17 +152,23 @@
return;
}
- // Store the previous volume if a device was active.
- if (mCurrentDevice != null) {
- storeVolume();
- }
-
// Wait until AudioManager informs us that the new device is connected
- mDeferredDevice = device;
+ mCurrentDevice = device;
// If device is null, that means that there is no active Bluetooth device
if (device == null) {
mCurrentDevice = null;
+ return;
+ }
+
+ // If the device is connected then switch the device which informs audio manager that
+ // absolute volume is supported and set the volume for the device. Otherwise disable
+ // absolute volume until the new device connects to prevent sending unattenuated audio.
+ if (mDeviceMap.containsKey(device)) {
+ switchVolumeDevice(device);
+ } else {
+ d("volumeDeviceSwitched: Set Absolute Volume support to false until device connects.");
+ mAudioManager.avrcpSupportsAbsoluteVolume(device.getAddress(), false);
}
}
@@ -220,7 +180,7 @@
public void dump(StringBuilder sb) {
sb.append("AvrcpVolumeManager:\n");
sb.append(" mCurrentDevice: " + mCurrentDevice + "\n");
- sb.append(" mDeferredDevice: " + mDeferredDevice + "\n");
+ sb.append(" Current System Volume: " + mAudioManager.getStreamVolume(STREAM_MUSIC) + "\n");
sb.append(" Device Volume Memory Map:\n");
sb.append(String.format(" %-17s : %-14s : %3s : %s\n",
"Device Address", "Device Name", "Vol", "AbsVol"));
diff --git a/android/app/src/com/android/bluetooth/newavrcp/MediaPlayerList.java b/android/app/src/com/android/bluetooth/newavrcp/MediaPlayerList.java
index 1316c77..0a6b946 100644
--- a/android/app/src/com/android/bluetooth/newavrcp/MediaPlayerList.java
+++ b/android/app/src/com/android/bluetooth/newavrcp/MediaPlayerList.java
@@ -194,10 +194,6 @@
player.disconnect();
}
mBrowsablePlayers.clear();
-
- mMediaPlayerIds = null;
- mMediaPlayers = null;
- mBrowsablePlayers = null;
}
int getCurrentPlayerId() {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
index 0cc9317..6b27256 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpServiceTest.java
@@ -90,6 +90,7 @@
TestUtils.setAdapterService(mAdapterService);
doReturn(MAX_CONNECTED_AUDIO_DEVICES).when(mAdapterService).getMaxConnectedAudioDevices();
+ doReturn(false).when(mAdapterService).isQuietModeEnabled();
mAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -851,18 +852,28 @@
}
/**
- * Helper function to test okToConnect() method
+ * Helper function to test okToConnect() method.
*
- * @param device test device
- * @param bondState bond state value, could be invalid
- * @param priority value, could be invalid, coudl be invalid
- * @param expected expected result from okToConnect()
+ * @param device test device
+ * @param bondState bond state value, could be invalid
+ * @param priority value, could be invalid, coudl be invalid
+ * @param expected expected result from okToConnect()
*/
private void testOkToConnectCase(BluetoothDevice device, int bondState, int priority,
boolean expected) {
doReturn(bondState).when(mAdapterService).getBondState(device);
Assert.assertTrue(mA2dpService.setPriority(device, priority));
- Assert.assertEquals(expected, mA2dpService.okToConnect(device));
- }
+ // Test when the AdapterService is in non-quiet mode: the result should not depend
+ // on whether the connection request is outgoing or incoming.
+ doReturn(false).when(mAdapterService).isQuietModeEnabled();
+ Assert.assertEquals(expected, mA2dpService.okToConnect(device, true)); // Outgoing
+ Assert.assertEquals(expected, mA2dpService.okToConnect(device, false)); // Incoming
+
+ // Test when the AdapterService is in quiet mode: the result should always be
+ // false when the connection request is incoming.
+ doReturn(true).when(mAdapterService).isQuietModeEnabled();
+ Assert.assertEquals(expected, mA2dpService.okToConnect(device, true)); // Outgoing
+ Assert.assertEquals(false, mA2dpService.okToConnect(device, false)); // Incoming
+ }
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java
index 7bbdc39..0b825bf 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java
@@ -107,7 +107,8 @@
* @param allow if true, connection is allowed
*/
private void allowConnection(boolean allow) {
- doReturn(allow).when(mA2dpService).okToConnect(any(BluetoothDevice.class));
+ doReturn(allow).when(mA2dpService).okToConnect(any(BluetoothDevice.class),
+ anyBoolean());
}
/**
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java
index b36b03d..37a9ded 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/PhonePolicyTest.java
@@ -151,8 +151,8 @@
mPhonePolicy.getBroadcastReceiver().onReceive(null /* context */, intent);
// Check that we got a request to connect over HFP and A2DP
- verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connect(eq(bondedDevices[0]));
verify(mA2dpService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connect(eq(bondedDevices[0]));
+ verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connect(eq(bondedDevices[0]));
}
/**
@@ -173,9 +173,6 @@
bondedDevices[3] = TestUtils.getTestDevice(mAdapter, 3);
when(mAdapterService.getBondedDevices()).thenReturn(bondedDevices);
- ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
- doAnswer(invocation -> connectedDevices).when(mHeadsetService).getConnectedDevices();
-
// Make all devices auto connect
when(mHeadsetService.getPriority(bondedDevices[0])).thenReturn(
BluetoothProfile.PRIORITY_AUTO_CONNECT);
@@ -186,76 +183,76 @@
when(mHeadsetService.getPriority(bondedDevices[3])).thenReturn(
BluetoothProfile.PRIORITY_OFF);
- // Make one of the device connected
- connectedDevices.add(bondedDevices[0]);
- when(mHeadsetService.getConnectionState(bondedDevices[0])).thenReturn(
- BluetoothProfile.STATE_CONNECTED);
- Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+ // Make one of the device active
+ Intent intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bondedDevices[0]);
- intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED);
- intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mPhonePolicy.getBroadcastReceiver().onReceive(null /* context */, intent);
// All other disconnected device's priority is set to ON, except disabled ones
verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setPriority(bondedDevices[0],
- BluetoothProfile.PRIORITY_AUTO_CONNECT);
+ BluetoothProfile.PRIORITY_ON);
verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setPriority(bondedDevices[1],
BluetoothProfile.PRIORITY_ON);
verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setPriority(bondedDevices[2],
BluetoothProfile.PRIORITY_ON);
+ verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setPriority(bondedDevices[0],
+ BluetoothProfile.PRIORITY_AUTO_CONNECT);
verify(mHeadsetService, never()).setPriority(eq(bondedDevices[3]), anyInt());
when(mHeadsetService.getPriority(bondedDevices[1])).thenReturn(
BluetoothProfile.PRIORITY_ON);
when(mHeadsetService.getPriority(bondedDevices[2])).thenReturn(
BluetoothProfile.PRIORITY_ON);
- // Make another device connected
- connectedDevices.add(bondedDevices[1]);
+ // Make another device active
when(mHeadsetService.getConnectionState(bondedDevices[1])).thenReturn(
BluetoothProfile.STATE_CONNECTED);
- intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+ intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bondedDevices[1]);
- intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED);
- intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mPhonePolicy.getBroadcastReceiver().onReceive(null /* context */, intent);
- // This device should be set to auto connect
+ // This device should be set to auto connect while the first device is reset to ON
+ verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setPriority(bondedDevices[0],
+ BluetoothProfile.PRIORITY_ON);
verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setPriority(bondedDevices[1],
BluetoothProfile.PRIORITY_AUTO_CONNECT);
verify(mHeadsetService, never()).setPriority(eq(bondedDevices[3]), anyInt());
+ when(mHeadsetService.getPriority(bondedDevices[0])).thenReturn(
+ BluetoothProfile.PRIORITY_ON);
when(mHeadsetService.getPriority(bondedDevices[1])).thenReturn(
BluetoothProfile.PRIORITY_AUTO_CONNECT);
- // Make one of the device disconnect
- connectedDevices.remove(bondedDevices[0]);
- when(mHeadsetService.getConnectionState(bondedDevices[0])).thenReturn(
+ // Set active device to null
+ when(mHeadsetService.getConnectionState(bondedDevices[1])).thenReturn(
BluetoothProfile.STATE_DISCONNECTED);
- intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bondedDevices[0]);
- intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTED);
- intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED);
+ intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, (BluetoothDevice) null);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mPhonePolicy.getBroadcastReceiver().onReceive(null /* context */, intent);
// This should not have any effect
- verify(mHeadsetService, after(ASYNC_CALL_TIMEOUT_MILLIS).never()).setPriority(
- bondedDevices[0], BluetoothProfile.PRIORITY_ON);
+ verify(mHeadsetService, after(ASYNC_CALL_TIMEOUT_MILLIS).times(1)).setPriority(
+ bondedDevices[1], BluetoothProfile.PRIORITY_ON);
+ // Make the current active device fail to connect
+ when(mHeadsetService.getConnectionState(bondedDevices[1])).thenReturn(
+ BluetoothProfile.STATE_DISCONNECTED);
+ when(mA2dpService.getConnectionState(bondedDevices[1])).thenReturn(
+ BluetoothProfile.STATE_DISCONNECTED);
intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bondedDevices[0]);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bondedDevices[1]);
intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mPhonePolicy.getBroadcastReceiver().onReceive(null /* context */, intent);
// This device should be set to ON
- verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setPriority(bondedDevices[0],
- BluetoothProfile.PRIORITY_ON);
+ verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).setPriority(
+ bondedDevices[1], BluetoothProfile.PRIORITY_ON);
// Verify that we are not setting priorities to random devices and values
- verify(mHeadsetService, times(5)).setPriority(any(BluetoothDevice.class), anyInt());
+ verify(mHeadsetService, times(7)).setPriority(any(BluetoothDevice.class), anyInt());
}
/**
@@ -304,6 +301,10 @@
/**
* Test that a second device will auto-connect if there is already one connected device.
+ *
+ * Even though we currently only set one device to be auto connect. The consumer of the auto
+ * connect property works independently so that we will connect to all devices that are in
+ * auto connect mode.
*/
@Test
public void testAutoConnectMultipleDevices() {
@@ -472,13 +473,14 @@
// Check the connect priorities for all devices
// - testDevices[0] - connected for HFP and A2DP: setPriority() should not be called
- // - testDevices[1] - connection state changed for HFP - auto-connect completed for A2DP
- // expect setPriority(PRIORITY_AUTO_CONNECT) for HFP
+ // - testDevices[1] - connection state changed for HFP should no longer trigger auto
+ // connect priority change since it is now triggered by A2DP active
+ // device change intent
// - testDevices[2] - connected for A2DP: setPriority() should not be called
// - testDevices[3] - not connected for HFP nor A2DP: setPriority() should not be called
verify(mHeadsetService, times(0)).setPriority(eq(testDevices[0]), anyInt());
verify(mA2dpService, times(0)).setPriority(eq(testDevices[0]), anyInt());
- verify(mHeadsetService, times(1)).setPriority(eq(testDevices[1]),
+ verify(mHeadsetService, times(0)).setPriority(eq(testDevices[1]),
eq(BluetoothProfile.PRIORITY_AUTO_CONNECT));
verify(mA2dpService, times(0)).setPriority(eq(testDevices[1]), anyInt());
verify(mHeadsetService, times(0)).setPriority(eq(testDevices[2]), anyInt());
@@ -508,15 +510,16 @@
// Check the connect priorities for all devices
// - testDevices[0] - connected for HFP and A2DP: setPriority() should not be called
// - testDevices[1] - connected for HFP and A2DP: setPriority() should not be called
- // - testDevices[2] - connection state changed for A2DP - auto-connect completed for HFP
- // expected setPriority(PRIORITY_AUTO_CONNECT) for A2DP
+ // - testDevices[2] - connection state changed for A2DP should no longer trigger auto
+ // connect priority change since it is now triggered by A2DP
+ // active device change intent
// - testDevices[3] - not connected for HFP nor A2DP: setPriority() should not be called
verify(mHeadsetService, times(0)).setPriority(eq(testDevices[0]), anyInt());
verify(mA2dpService, times(0)).setPriority(eq(testDevices[0]), anyInt());
verify(mHeadsetService, times(0)).setPriority(eq(testDevices[1]), anyInt());
verify(mA2dpService, times(0)).setPriority(eq(testDevices[1]), anyInt());
verify(mHeadsetService, times(0)).setPriority(eq(testDevices[2]), anyInt());
- verify(mA2dpService, times(1)).setPriority(eq(testDevices[2]),
+ verify(mA2dpService, times(0)).setPriority(eq(testDevices[2]),
eq(BluetoothProfile.PRIORITY_AUTO_CONNECT));
verify(mHeadsetService, times(0)).setPriority(eq(testDevices[3]), anyInt());
verify(mA2dpService, times(0)).setPriority(eq(testDevices[3]), anyInt());