audio: Remove notification if hot plugged device is activated manually
Handles the situation when a hotplugged device which triggers the
notification has been activated by users via settings or quick settings,
rather than via the switch button on notification body.
Bug: b/328425880
Test: CrasAudioHandlerTest
Change-Id: I9eca12073022d9b102c4301171fb550d2efde216
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5606668
Reviewed-by: Longbo Wei <longbowei@google.com>
Commit-Queue: Wenyu Zhang <zhangwenyu@google.com>
Cr-Commit-Position: refs/heads/main@{#1312120}
diff --git a/chromeos/ash/components/audio/audio_selection_notification_handler.cc b/chromeos/ash/components/audio/audio_selection_notification_handler.cc
index 9955cc4..b8768c0 100644
--- a/chromeos/ash/components/audio/audio_selection_notification_handler.cc
+++ b/chromeos/ash/components/audio/audio_selection_notification_handler.cc
@@ -392,11 +392,11 @@
}
void AudioSelectionNotificationHandler::RemoveNotificationIfNecessary(
- const AudioDeviceList& removed_devices) {
- const AudioDeviceList& hotplug_devices = removed_devices.front().is_input
- ? hotplug_input_devices_
- : hotplug_output_devices_;
- for (const AudioDevice& device : removed_devices) {
+ const AudioDeviceList& removed_or_activated_devices) {
+ const AudioDeviceList& hotplug_devices =
+ removed_or_activated_devices.front().is_input ? hotplug_input_devices_
+ : hotplug_output_devices_;
+ for (const AudioDevice& device : removed_or_activated_devices) {
if (IsDeviceInList(device, hotplug_devices)) {
// Remove notification and hotplug_input/output_devices_.
auto* message_center = message_center::MessageCenter::Get();
diff --git a/chromeos/ash/components/audio/audio_selection_notification_handler.h b/chromeos/ash/components/audio/audio_selection_notification_handler.h
index 1bd5dff..da62555c2 100644
--- a/chromeos/ash/components/audio/audio_selection_notification_handler.h
+++ b/chromeos/ash/components/audio/audio_selection_notification_handler.h
@@ -99,8 +99,11 @@
OpenSettingsAudioPageCallback open_settings_audio_page_callback);
// Handles the situation when a hotplugged device which triggers the
- // notification has been removed. Remove the notification in this case.
- void RemoveNotificationIfNecessary(const AudioDeviceList& removed_devices);
+ // notification has been removed, or has been activated by users via settings
+ // or quick settings, rather than via the switch button on notification body.
+ // Remove the notification in these cases.
+ void RemoveNotificationIfNecessary(
+ const AudioDeviceList& removed_or_activated_devices);
private:
// Grant friend access for comprehensive testing of private/protected members.
diff --git a/chromeos/ash/components/audio/cras_audio_handler.cc b/chromeos/ash/components/audio/cras_audio_handler.cc
index e0e8c0a..0284fbf 100644
--- a/chromeos/ash/components/audio/cras_audio_handler.cc
+++ b/chromeos/ash/components/audio/cras_audio_handler.cc
@@ -1234,6 +1234,11 @@
if (features::IsAudioSelectionImprovementEnabled()) {
SyncDevicePrefSetMap(active_device.is_input);
audio_pref_handler_->UpdateMostRecentActivatedDeviceIdList(active_device);
+
+ // Remove notification if the hotplugged device that triggered the
+ // notification has already been activated.
+ audio_selection_notification_handler_.RemoveNotificationIfNecessary(
+ {active_device});
}
// Save active state for the nodes.
diff --git a/chromeos/ash/components/audio/cras_audio_handler_unittest.cc b/chromeos/ash/components/audio/cras_audio_handler_unittest.cc
index 51143fc..0597786 100644
--- a/chromeos/ash/components/audio/cras_audio_handler_unittest.cc
+++ b/chromeos/ash/components/audio/cras_audio_handler_unittest.cc
@@ -7655,4 +7655,51 @@
EXPECT_EQ(device2->device_name, input_device_name);
}
+// Tests that notification is removed if the hot plugged device that triggered
+// the notification has already been activated via settings or quick settings.
+TEST_P(
+ CrasAudioHandlerTest,
+ RemoveNotificationIfHotPluggedDeviceHasBeenActivated_AudioSelectionImprovementFlagOn) {
+ scoped_feature_list_.InitAndEnableFeature(
+ ash::features::kAudioSelectionImprovement);
+
+ // Initialize with internal speaker.
+ SetupAudioNodesAndExpectActiveNodes(
+ /*initial_nodes=*/{kInternalSpeaker},
+ /*expected_active_input_node=*/nullptr,
+ /*expected_active_output_node=*/kInternalSpeaker,
+ /*expected_has_alternative_input=*/std::nullopt,
+ /*expected_has_alternative_output=*/false);
+
+ // Expect that notification is not displayed since there is only one output
+ // device connected.
+ EXPECT_EQ(0u, GetNotificationCount());
+
+ // Plug in a usb headphone.
+ AudioNodeList audio_nodes;
+ AudioNode internal_speaker = GenerateAudioNode(kInternalSpeaker);
+ internal_speaker.active = true;
+ audio_nodes.push_back(internal_speaker);
+ AudioNode usb_headphone_1 = GenerateAudioNode(kUSBHeadphone1);
+ audio_nodes.push_back(usb_headphone_1);
+ ChangeAudioNodes(audio_nodes);
+
+ // Verify the active output device is not switched because the new connected
+ // device is not seen before.
+ EXPECT_EQ(0, test_observer_->active_output_node_changed_count());
+ ExpectActiveDevice(/*is_input=*/false,
+ /*expected_active_device=*/kInternalSpeaker,
+ /*has_alternative_device=*/true);
+
+ // Verify notification is displayed.
+ FastForwardBy(AudioSelectionNotificationHandler::kDebounceTime);
+ EXPECT_EQ(1u, GetNotificationCount());
+
+ // Manually activate the kUSBHeadphone1, expect that notification is removed.
+ AudioDevice usb_headphone_device(usb_headphone_1);
+ cras_audio_handler_->SwitchToDevice(usb_headphone_device, true,
+ DeviceActivateType::kActivateByUser);
+ EXPECT_EQ(0u, GetNotificationCount());
+}
+
} // namespace ash