Loading system/bta/vc/vc.cc +25 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <base/strings/string_number_conversions.h> #include <base/strings/string_util.h> #include <bluetooth/log.h> #include <com_android_bluetooth_flags.h> #include <hardware/bt_gatt_types.h> #include <hardware/bt_vc.h> #include <stdio.h> Loading Loading @@ -934,6 +935,27 @@ public: } } bool isPendingVolumeControlOperation(const RawAddress& addr) { if (!com::android::bluetooth::flags::vcp_allow_set_same_volume_if_pending()) { return false; } if (std::find_if(ongoing_operations_.begin(), ongoing_operations_.end(), [&addr](const VolumeOperation& op) { auto it = find(op.devices_.begin(), op.devices_.end(), addr); if (it != op.devices_.end()) { bluetooth::log::debug( "There is a pending volume operation {} for device {}", op.operation_id_, addr); return true; } return false; }) != ongoing_operations_.end()) { return true; } return false; } void RemovePendingVolumeControlOperations(const std::vector<RawAddress>& devices, int group_id) { bluetooth::log::debug(""); for (auto op = ongoing_operations_.begin(); op != ongoing_operations_.end();) { Loading Loading @@ -1156,7 +1178,8 @@ public: volume_control_devices_.FindByAddress(std::get<RawAddress>(addr_or_group_id)); if (dev != nullptr) { bluetooth::log::debug("Address: {}: isReady: {}", dev->address, dev->IsReady()); if (dev->IsReady() && (dev->volume != volume)) { if (dev->IsReady() && ((dev->volume != volume) || isPendingVolumeControlOperation(dev->address))) { std::vector<RawAddress> devices = {dev->address}; RemovePendingVolumeControlOperations(devices, bluetooth::groups::kGroupUnknown); PrepareVolumeControlOperation(devices, bluetooth::groups::kGroupUnknown, false, opcode, Loading Loading @@ -1189,7 +1212,7 @@ public: continue; } if (!dev->IsReady() || (dev->volume == volume)) { if (!dev->IsReady() || ((dev->volume == volume) && !isPendingVolumeControlOperation(*it))) { it = devices.erase(it); volumeNotChanged = volumeNotChanged ? volumeNotChanged : (dev->volume == volume); deviceNotReady = deviceNotReady ? deviceNotReady : !dev->IsReady(); Loading system/bta/vc/vc_test.cc +41 −0 Original line number Diff line number Diff line Loading @@ -1703,6 +1703,47 @@ TEST_F(VolumeControlValueSetTest, test_set_volume) { VolumeControl::Get()->SetVolume(test_address, 0x20); } TEST_F(VolumeControlValueSetTest, test_set_volume_to_previous_during_pending) { com::android::bluetooth::flags::provider_->vcp_allow_set_same_volume_if_pending(true); // In this test we simulate notification coming later and operations will be queued ON_CALL(gatt_queue, WriteCharacteristic(conn_id, 0x0024, _, GATT_WRITE, _, _)) .WillByDefault([](uint16_t conn_id, uint16_t handle, std::vector<uint8_t> value, tGATT_WRITE_TYPE /*write_type*/, GATT_WRITE_OP_CB cb, void* cb_data) { uint8_t write_rsp; switch (value[0]) { case 0x04: // set abs. volume break; default: break; } cb(conn_id, GATT_SUCCESS, handle, 0, &write_rsp, cb_data); }); const std::vector<uint8_t> vol_x10({0x04, /*change_cnt*/ 0, 0x10}); std::vector<uint8_t> ntf_value_x10({0x10, 0, 1}); const std::vector<uint8_t> vol_x11({0x04, /*change_cnt*/ 1, 0x11}); std::vector<uint8_t> ntf_value_x11({0x11, 0, 2}); const std::vector<uint8_t> vol_x10_2({0x04, /*change_cnt*/ 2, 0x10}); std::vector<uint8_t> ntf_value_x10_2({0x10, 0, 3}); EXPECT_CALL(gatt_queue, WriteCharacteristic(conn_id, 0x0024, vol_x10, GATT_WRITE, _, _)).Times(1); VolumeControl::Get()->SetVolume(test_address, 0x10); GetNotificationEvent(0x0021, ntf_value_x10); EXPECT_CALL(gatt_queue, WriteCharacteristic(conn_id, 0x0024, vol_x11, GATT_WRITE, _, _)).Times(1); EXPECT_CALL(gatt_queue, WriteCharacteristic(conn_id, 0x0024, vol_x10_2, GATT_WRITE, _, _)) .Times(1); VolumeControl::Get()->SetVolume(test_address, 0x11); VolumeControl::Get()->SetVolume(test_address, 0x10); GetNotificationEvent(0x0021, ntf_value_x11); GetNotificationEvent(0x0021, ntf_value_x10_2); Mock::VerifyAndClearExpectations(&gatt_queue); } TEST_F(VolumeControlValueSetTest, test_set_volume_stress) { uint8_t n = 100; uint8_t change_cnt = 0; Loading Loading
system/bta/vc/vc.cc +25 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <base/strings/string_number_conversions.h> #include <base/strings/string_util.h> #include <bluetooth/log.h> #include <com_android_bluetooth_flags.h> #include <hardware/bt_gatt_types.h> #include <hardware/bt_vc.h> #include <stdio.h> Loading Loading @@ -934,6 +935,27 @@ public: } } bool isPendingVolumeControlOperation(const RawAddress& addr) { if (!com::android::bluetooth::flags::vcp_allow_set_same_volume_if_pending()) { return false; } if (std::find_if(ongoing_operations_.begin(), ongoing_operations_.end(), [&addr](const VolumeOperation& op) { auto it = find(op.devices_.begin(), op.devices_.end(), addr); if (it != op.devices_.end()) { bluetooth::log::debug( "There is a pending volume operation {} for device {}", op.operation_id_, addr); return true; } return false; }) != ongoing_operations_.end()) { return true; } return false; } void RemovePendingVolumeControlOperations(const std::vector<RawAddress>& devices, int group_id) { bluetooth::log::debug(""); for (auto op = ongoing_operations_.begin(); op != ongoing_operations_.end();) { Loading Loading @@ -1156,7 +1178,8 @@ public: volume_control_devices_.FindByAddress(std::get<RawAddress>(addr_or_group_id)); if (dev != nullptr) { bluetooth::log::debug("Address: {}: isReady: {}", dev->address, dev->IsReady()); if (dev->IsReady() && (dev->volume != volume)) { if (dev->IsReady() && ((dev->volume != volume) || isPendingVolumeControlOperation(dev->address))) { std::vector<RawAddress> devices = {dev->address}; RemovePendingVolumeControlOperations(devices, bluetooth::groups::kGroupUnknown); PrepareVolumeControlOperation(devices, bluetooth::groups::kGroupUnknown, false, opcode, Loading Loading @@ -1189,7 +1212,7 @@ public: continue; } if (!dev->IsReady() || (dev->volume == volume)) { if (!dev->IsReady() || ((dev->volume == volume) && !isPendingVolumeControlOperation(*it))) { it = devices.erase(it); volumeNotChanged = volumeNotChanged ? volumeNotChanged : (dev->volume == volume); deviceNotReady = deviceNotReady ? deviceNotReady : !dev->IsReady(); Loading
system/bta/vc/vc_test.cc +41 −0 Original line number Diff line number Diff line Loading @@ -1703,6 +1703,47 @@ TEST_F(VolumeControlValueSetTest, test_set_volume) { VolumeControl::Get()->SetVolume(test_address, 0x20); } TEST_F(VolumeControlValueSetTest, test_set_volume_to_previous_during_pending) { com::android::bluetooth::flags::provider_->vcp_allow_set_same_volume_if_pending(true); // In this test we simulate notification coming later and operations will be queued ON_CALL(gatt_queue, WriteCharacteristic(conn_id, 0x0024, _, GATT_WRITE, _, _)) .WillByDefault([](uint16_t conn_id, uint16_t handle, std::vector<uint8_t> value, tGATT_WRITE_TYPE /*write_type*/, GATT_WRITE_OP_CB cb, void* cb_data) { uint8_t write_rsp; switch (value[0]) { case 0x04: // set abs. volume break; default: break; } cb(conn_id, GATT_SUCCESS, handle, 0, &write_rsp, cb_data); }); const std::vector<uint8_t> vol_x10({0x04, /*change_cnt*/ 0, 0x10}); std::vector<uint8_t> ntf_value_x10({0x10, 0, 1}); const std::vector<uint8_t> vol_x11({0x04, /*change_cnt*/ 1, 0x11}); std::vector<uint8_t> ntf_value_x11({0x11, 0, 2}); const std::vector<uint8_t> vol_x10_2({0x04, /*change_cnt*/ 2, 0x10}); std::vector<uint8_t> ntf_value_x10_2({0x10, 0, 3}); EXPECT_CALL(gatt_queue, WriteCharacteristic(conn_id, 0x0024, vol_x10, GATT_WRITE, _, _)).Times(1); VolumeControl::Get()->SetVolume(test_address, 0x10); GetNotificationEvent(0x0021, ntf_value_x10); EXPECT_CALL(gatt_queue, WriteCharacteristic(conn_id, 0x0024, vol_x11, GATT_WRITE, _, _)).Times(1); EXPECT_CALL(gatt_queue, WriteCharacteristic(conn_id, 0x0024, vol_x10_2, GATT_WRITE, _, _)) .Times(1); VolumeControl::Get()->SetVolume(test_address, 0x11); VolumeControl::Get()->SetVolume(test_address, 0x10); GetNotificationEvent(0x0021, ntf_value_x11); GetNotificationEvent(0x0021, ntf_value_x10_2); Mock::VerifyAndClearExpectations(&gatt_queue); } TEST_F(VolumeControlValueSetTest, test_set_volume_stress) { uint8_t n = 100; uint8_t change_cnt = 0; Loading