microphone_mute_notification_controller.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/system/microphone_mute/microphone_mute_notification_controller.h"
  5. #include <cstdint>
  6. #include <string>
  7. #include "ash/constants/notifier_catalogs.h"
  8. #include "ash/public/cpp/microphone_mute_notification_delegate.h"
  9. #include "ash/public/cpp/notification_utils.h"
  10. #include "ash/strings/grit/ash_strings.h"
  11. #include "base/bind.h"
  12. #include "base/strings/utf_string_conversions.h"
  13. #include "components/vector_icons/vector_icons.h"
  14. #include "ui/base/l10n/l10n_util.h"
  15. #include "ui/message_center/message_center.h"
  16. namespace ash {
  17. // static
  18. const char MicrophoneMuteNotificationController::kNotificationId[] =
  19. "ash://microphone_mute";
  20. MicrophoneMuteNotificationController::MicrophoneMuteNotificationController() {
  21. audio_observation_.Observe(CrasAudioHandler::Get());
  22. }
  23. MicrophoneMuteNotificationController::~MicrophoneMuteNotificationController() =
  24. default;
  25. void MicrophoneMuteNotificationController::OnInputMuteChanged(bool mute_on) {
  26. mic_mute_on_ = mute_on;
  27. mic_muted_by_mute_switch_ =
  28. CrasAudioHandler::Get()->input_muted_by_microphone_mute_switch();
  29. // Show the notification with low priority when the mute state changes, so the
  30. // notification gets shown silently. This prevents the notification from
  31. // interfering with the mute state change toast that gets shown on mute state
  32. // change.
  33. MaybeShowNotification(
  34. current_notification_priority_.value_or(message_center::LOW_PRIORITY),
  35. /*recreate=*/false);
  36. }
  37. void MicrophoneMuteNotificationController::
  38. OnInputMutedByMicrophoneMuteSwitchChanged(bool muted) {
  39. if (mic_muted_by_mute_switch_ == muted)
  40. return;
  41. mic_muted_by_mute_switch_ = muted;
  42. // Show the notification with low priority when the mute state changes, so the
  43. // notification gets shown silently. This prevents the notification from
  44. // interfering with the mute state change toast that gets shown on mute state
  45. // change.
  46. MaybeShowNotification(
  47. current_notification_priority_.value_or(message_center::LOW_PRIORITY),
  48. /*recreate=*/false);
  49. }
  50. void MicrophoneMuteNotificationController::
  51. OnNumberOfInputStreamsWithPermissionChanged() {
  52. // Catches the case where a mic-using app is launched while the mic is muted.
  53. const int input_stream_count = CountActiveInputStreams();
  54. const bool stream_count_decreased = input_stream_count < input_stream_count_;
  55. input_stream_count_ = input_stream_count;
  56. if (!input_stream_count_) {
  57. RemoveMicrophoneMuteNotification();
  58. return;
  59. }
  60. MaybeShowNotification(message_center::DEFAULT_PRIORITY,
  61. /*recreate=*/!stream_count_decreased);
  62. }
  63. void MicrophoneMuteNotificationController::MaybeShowNotification(
  64. message_center::NotificationPriority priority,
  65. bool recreate) {
  66. if (mic_mute_on_) {
  67. auto* microphone_mute_notification_delegate =
  68. MicrophoneMuteNotificationDelegate::Get();
  69. // `MicrophoneMuteNotificationDelegate` is not created in guest mode.
  70. if (!microphone_mute_notification_delegate)
  71. return;
  72. absl::optional<std::u16string> app_name =
  73. microphone_mute_notification_delegate->GetAppAccessingMicrophone();
  74. if (app_name.has_value() || input_stream_count_) {
  75. if (recreate)
  76. RemoveMicrophoneMuteNotification();
  77. std::unique_ptr<message_center::Notification> notification =
  78. GenerateMicrophoneMuteNotification(app_name, priority);
  79. message_center::MessageCenter::Get()->AddNotification(
  80. std::move(notification));
  81. return;
  82. }
  83. }
  84. RemoveMicrophoneMuteNotification();
  85. }
  86. std::unique_ptr<message_center::Notification>
  87. MicrophoneMuteNotificationController::GenerateMicrophoneMuteNotification(
  88. const absl::optional<std::u16string>& app_name,
  89. message_center::NotificationPriority priority) {
  90. message_center::RichNotificationData notification_data;
  91. notification_data.priority = priority;
  92. current_notification_priority_ = priority;
  93. notification_data.pinned = true;
  94. scoped_refptr<message_center::NotificationDelegate> delegate;
  95. // Don't show a button to unmute device if the microphone was muted by a HW
  96. // mute switch, as in that case unmute action would not work.
  97. if (!mic_muted_by_mute_switch_) {
  98. notification_data.buttons.emplace_back(l10n_util::GetStringUTF16(
  99. IDS_MICROPHONE_MUTED_NOTIFICATION_ACTION_BUTTON));
  100. delegate =
  101. base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
  102. base::BindRepeating([](absl::optional<int> button_index) {
  103. // Click on the notification body is no-op.
  104. if (!button_index)
  105. return;
  106. CrasAudioHandler::Get()->SetInputMute(false);
  107. }));
  108. }
  109. std::unique_ptr<message_center::Notification> notification =
  110. CreateSystemNotification(
  111. message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId,
  112. GetNotificationTitle(app_name), GetNotificationMessage(),
  113. /*display_source=*/std::u16string(), GURL(),
  114. message_center::NotifierId(
  115. message_center::NotifierType::SYSTEM_COMPONENT, kNotificationId,
  116. NotificationCatalogName::kMicrophoneMute),
  117. notification_data, delegate, vector_icons::kSettingsIcon,
  118. message_center::SystemNotificationWarningLevel::NORMAL);
  119. return notification;
  120. }
  121. std::u16string MicrophoneMuteNotificationController::GetNotificationMessage()
  122. const {
  123. return mic_muted_by_mute_switch_
  124. ? l10n_util::GetStringUTF16(
  125. IDS_MICROPHONE_MUTE_SWITCH_ON_NOTIFICATION_MESSAGE)
  126. : l10n_util::GetStringUTF16(
  127. IDS_MICROPHONE_MUTED_NOTIFICATION_MESSAGE);
  128. }
  129. std::u16string MicrophoneMuteNotificationController::GetNotificationTitle(
  130. const absl::optional<std::u16string>& app_name) const {
  131. return !app_name.value_or(u"").empty()
  132. ? l10n_util::GetStringFUTF16(
  133. IDS_MICROPHONE_MUTED_NOTIFICATION_TITLE_WITH_APP_NAME,
  134. app_name.value())
  135. : l10n_util::GetStringUTF16(
  136. IDS_MICROPHONE_MUTED_NOTIFICATION_TITLE);
  137. }
  138. void MicrophoneMuteNotificationController::RemoveMicrophoneMuteNotification() {
  139. current_notification_priority_.reset();
  140. message_center::MessageCenter::Get()->RemoveNotification(kNotificationId,
  141. /*by_user=*/false);
  142. }
  143. int MicrophoneMuteNotificationController::CountActiveInputStreams() {
  144. int num_active_streams = 0;
  145. base::flat_map<CrasAudioHandler::ClientType, uint32_t> input_streams =
  146. CrasAudioHandler::Get()->GetNumberOfInputStreamsWithPermission();
  147. for (auto& client_type_info : input_streams)
  148. num_active_streams += client_type_info.second;
  149. return num_active_streams;
  150. }
  151. } // namespace ash