| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROMEOS_ASH_COMPONENTS_AUDIO_AUDIO_SELECTION_NOTIFICATION_HANDLER_H_ |
| #define CHROMEOS_ASH_COMPONENTS_AUDIO_AUDIO_SELECTION_NOTIFICATION_HANDLER_H_ |
| |
| #include <optional> |
| |
| #include "base/component_export.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "chromeos/ash/components/audio/audio_device.h" |
| #include "chromeos/ash/components/audio/audio_device_id.h" |
| #include "chromeos/ash/components/audio/audio_device_metrics_handler.h" |
| #include "chromeos/ash/components/audio/device_activate_type.h" |
| #include "ui/message_center/message_center.h" |
| |
| namespace ash { |
| |
| // A callback of CrasAudioHandler::SwitchToDevice function, used to handle the |
| // switch button on audio selection notification being clicked. |
| using SwitchToDeviceCallback = |
| base::RepeatingCallback<void(const AudioDevice& device, |
| bool notify, |
| DeviceActivateType activate_by)>; |
| |
| // A callback function to open OS Settings audio page. |
| using OpenSettingsAudioPageCallback = base::RepeatingCallback<void()>; |
| |
| // AudioSelectionNotificationHandler handles the creation and display of the |
| // audio selection notification. |
| class COMPONENT_EXPORT(CHROMEOS_ASH_COMPONENTS_AUDIO) |
| AudioSelectionNotificationHandler { |
| public: |
| AudioSelectionNotificationHandler(); |
| AudioSelectionNotificationHandler(const AudioSelectionNotificationHandler&) = |
| delete; |
| AudioSelectionNotificationHandler& operator=( |
| const AudioSelectionNotificationHandler&) = delete; |
| ~AudioSelectionNotificationHandler(); |
| |
| // Time delta to debounce the audio selection notification. |
| static constexpr base::TimeDelta kDebounceTime = base::Milliseconds(1500); |
| |
| // The audio selection notification id, used to identify the notification |
| // itself. |
| static constexpr char kAudioSelectionNotificationId[] = |
| "audio_selection_notification"; |
| |
| // The audio selection notifier id. |
| static constexpr char kAudioSelectionNotifierId[] = |
| "ash.audio_selection_notification_handler"; |
| |
| // Different types of audio selection notification. |
| // Do not reorder since it's used in histogram metrics. |
| enum class NotificationType { |
| // A single audio device source with only input audio device. e.g. a web |
| // cam. |
| kSingleSourceWithInputOnly = 0, |
| // A single audio device source with only output audio device. e.g. a HDMI |
| // display. |
| kSingleSourceWithOutputOnly = 1, |
| // A single audio device source with both input and output audio devices. |
| // e.g. a USB audio device. |
| kSingleSourceWithInputAndOutput = 2, |
| // Multiple audio device sources, e.g. a web cam and a HDMI display. |
| kMultipleSources = 3, |
| kMaxValue = kMultipleSources, |
| }; |
| |
| // Stores minimal info to create a notification. The device names will be |
| // displayed in notification body. If the notification type is |
| // kMultipleSources, device name refers to currently activated device name. |
| // Otherwise, device name refers to hot plugged device name. |
| struct NotificationTemplate { |
| NotificationTemplate(NotificationType type, |
| std::optional<std::string> input_device_name, |
| std::optional<std::string> output_device_name); |
| ~NotificationTemplate(); |
| |
| NotificationType type; |
| std::optional<std::string> input_device_name; |
| std::optional<std::string> output_device_name; |
| }; |
| |
| // Creates and displays an audio selection notification to let users make the |
| // switching or not switching decision. |
| // TODO(b/333608911): Revisit audio selection notification after updated audio |
| // sliders in quick settings. |
| void ShowAudioSelectionNotification( |
| const AudioDeviceList& hotplug_input_devices, |
| const AudioDeviceList& hotplug_output_devices, |
| const std::optional<std::string>& active_input_device_name, |
| const std::optional<std::string>& active_output_device_name, |
| SwitchToDeviceCallback switch_to_device_callback, |
| OpenSettingsAudioPageCallback open_settings_audio_page_callback); |
| |
| // 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. Remove the |
| // notification in this case. |
| void RemoveNotificationIfHotpluggedDeviceActivated( |
| const AudioDeviceList& activated_devices); |
| |
| // Handles the situation when a hotplugged device which triggers the |
| // notification has been removed. Remove the notification in this case. |
| void RemoveNotificationIfHotpluggedDeviceDisconnected( |
| bool is_input, |
| const AudioDeviceList& current_devices); |
| |
| private: |
| // Grant friend access for comprehensive testing of private/protected members. |
| friend class AudioSelectionNotificationHandlerTest; |
| |
| // Handles when the switch button is clicked. |
| void HandleSwitchButtonClicked( |
| const AudioDeviceList& devices_to_activate, |
| SwitchToDeviceCallback switch_to_device_callback, |
| NotificationType notification_type, |
| std::optional<int> button_index); |
| |
| // Handles when the settings button is clicked. |open_settigns_callback| is |
| // the callback to open the system settings audio page. |button_index| |
| // indicates the index of the button on notification body that is clicked. |
| void HandleSettingsButtonClicked( |
| OpenSettingsAudioPageCallback open_settigns_callback, |
| std::optional<int> button_index); |
| |
| // Checks if one audio input device and one audio output device belong to the |
| // same physical audio device. |
| bool AudioNodesBelongToSameSource(const AudioDevice& input_device, |
| const AudioDevice& output_device); |
| |
| // Gets necessary information to create and display notitification, such as |
| // notitication type and device name. |
| NotificationTemplate GetNotificationTemplate( |
| const AudioDeviceList& hotplug_input_devices, |
| const AudioDeviceList& hotplug_output_devices, |
| const std::optional<std::string>& active_input_device_name, |
| const std::optional<std::string>& active_output_device_name); |
| |
| // A helper function to determine notification type and show notification. |
| void ShowNotification( |
| const std::optional<std::string>& active_input_device_name, |
| const std::optional<std::string>& active_output_device_name, |
| SwitchToDeviceCallback switch_to_device_callback, |
| OpenSettingsAudioPageCallback open_settings_audio_page_callback); |
| |
| // Handles firing of audio selection related metrics. |
| AudioDeviceMetricsHandler audio_device_metrics_handler_; |
| |
| // The hotplugged devices that trigger the notification. Clear the list if the |
| // notification is removed. |
| AudioDeviceList hotplug_input_devices_; |
| AudioDeviceList hotplug_output_devices_; |
| |
| // Used to debounce the notification. |
| base::RetainingOneShotTimer show_notification_debounce_timer_; |
| |
| base::WeakPtrFactory<AudioSelectionNotificationHandler> weak_ptr_factory_{ |
| this}; |
| }; |
| |
| } // namespace ash |
| |
| #endif // CHROMEOS_ASH_COMPONENTS_AUDIO_AUDIO_SELECTION_NOTIFICATION_HANDLER_H_ |