notification_icons_controller.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright 2020 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/unified/notification_icons_controller.h"
  5. #include "ash/constants/ash_features.h"
  6. #include "ash/public/cpp/vm_camera_mic_constants.h"
  7. #include "ash/resources/vector_icons/vector_icons.h"
  8. #include "ash/session/session_controller_impl.h"
  9. #include "ash/shell.h"
  10. #include "ash/strings/grit/ash_strings.h"
  11. #include "ash/system/message_center/ash_message_center_lock_screen_controller.h"
  12. #include "ash/system/message_center/message_center_utils.h"
  13. #include "ash/system/tray/tray_constants.h"
  14. #include "ash/system/tray/tray_container.h"
  15. #include "ash/system/tray/tray_utils.h"
  16. #include "ash/system/unified/notification_counter_view.h"
  17. #include "ash/system/unified/unified_system_tray.h"
  18. #include "ash/system/unified/unified_system_tray_model.h"
  19. #include "ui/base/l10n/l10n_util.h"
  20. #include "ui/color/color_id.h"
  21. #include "ui/color/color_provider.h"
  22. #include "ui/gfx/paint_vector_icon.h"
  23. #include "ui/message_center/message_center.h"
  24. #include "ui/message_center/public/cpp/notification.h"
  25. #include "ui/message_center/vector_icons.h"
  26. #include "ui/views/border.h"
  27. #include "ui/views/controls/image_view.h"
  28. #include "ui/views/controls/separator.h"
  29. namespace ash {
  30. namespace {
  31. // Maximum number of notification icons shown in the system tray button.
  32. constexpr int kMaxNotificationIconsShown = 2;
  33. constexpr int kNotificationIconSpacing = 1;
  34. const char kCapsLockNotifierId[] = "ash.caps-lock";
  35. const char kBatteryNotificationNotifierId[] = "ash.battery";
  36. const char kUsbNotificationNotifierId[] = "ash.power";
  37. bool ShouldShowNotification(message_center::Notification* notification) {
  38. SessionControllerImpl* session_controller =
  39. Shell::Get()->session_controller();
  40. if (!session_controller->ShouldShowNotificationTray() ||
  41. (session_controller->IsScreenLocked() &&
  42. !AshMessageCenterLockScreenController::IsEnabled())) {
  43. return false;
  44. }
  45. std::string notifier_id = notification->notifier_id().id;
  46. if (message_center::MessageCenter::Get()->IsQuietMode() &&
  47. notifier_id != kCapsLockNotifierId) {
  48. return false;
  49. }
  50. // We don't want to show these notifications since the information is already
  51. // indicated by another item in tray.
  52. if (notifier_id == kVmCameraMicNotifierId ||
  53. notifier_id == kBatteryNotificationNotifierId ||
  54. notifier_id == kUsbNotificationNotifierId)
  55. return false;
  56. // We only show notification icon in the tray if it is either:
  57. // * Pinned (generally used for background process such as sharing your
  58. // screen, capslock, etc.).
  59. // * Critical warning (display failure, disk space critically low, etc.).
  60. return notification->pinned() ||
  61. notification->system_notification_warning_level() ==
  62. message_center::SystemNotificationWarningLevel::CRITICAL_WARNING;
  63. }
  64. } // namespace
  65. NotificationIconTrayItemView::NotificationIconTrayItemView(
  66. Shelf* shelf,
  67. NotificationIconsController* controller)
  68. : TrayItemView(shelf), controller_(controller) {
  69. CreateImageView();
  70. image_view()->SetBorder(
  71. views::CreateEmptyBorder(gfx::Insets::VH(0, kNotificationIconSpacing)));
  72. }
  73. NotificationIconTrayItemView::~NotificationIconTrayItemView() = default;
  74. void NotificationIconTrayItemView::SetNotification(
  75. message_center::Notification* notification) {
  76. notification_id_ = notification->id();
  77. if (!GetWidget())
  78. return;
  79. const auto* color_provider = GetColorProvider();
  80. gfx::Image masked_small_icon = notification->GenerateMaskedSmallIcon(
  81. kUnifiedTrayIconSize,
  82. TrayIconColor(Shell::Get()->session_controller()->GetSessionState()),
  83. color_provider->GetColor(ui::kColorNotificationIconBackground),
  84. color_provider->GetColor(ui::kColorNotificationIconForeground));
  85. if (!masked_small_icon.IsEmpty()) {
  86. image_view()->SetImage(masked_small_icon.AsImageSkia());
  87. } else {
  88. image_view()->SetImage(gfx::CreateVectorIcon(
  89. message_center::kProductIcon, kUnifiedTrayIconSize,
  90. TrayIconColor(Shell::Get()->session_controller()->GetSessionState())));
  91. }
  92. image_view()->SetTooltipText(notification->title());
  93. }
  94. void NotificationIconTrayItemView::Reset() {
  95. notification_id_ = std::string();
  96. image_view()->SetImage(gfx::ImageSkia());
  97. image_view()->SetTooltipText(std::u16string());
  98. }
  99. const std::u16string& NotificationIconTrayItemView::GetAccessibleNameString()
  100. const {
  101. if (notification_id_.empty())
  102. return base::EmptyString16();
  103. return image_view()->GetTooltipText();
  104. }
  105. const std::string& NotificationIconTrayItemView::GetNotificationId() const {
  106. return notification_id_;
  107. }
  108. void NotificationIconTrayItemView::HandleLocaleChange() {}
  109. const char* NotificationIconTrayItemView::GetClassName() const {
  110. return "NotificationIconTrayItemView";
  111. }
  112. void NotificationIconTrayItemView::OnThemeChanged() {
  113. TrayItemView::OnThemeChanged();
  114. controller_->UpdateNotificationIcons();
  115. }
  116. NotificationIconsController::NotificationIconsController(
  117. UnifiedSystemTray* tray)
  118. : tray_(tray) {
  119. system_tray_model_observation_.Observe(tray_->model().get());
  120. message_center::MessageCenter::Get()->AddObserver(this);
  121. Shell::Get()->session_controller()->AddObserver(this);
  122. }
  123. NotificationIconsController::~NotificationIconsController() {
  124. message_center::MessageCenter::Get()->RemoveObserver(this);
  125. Shell::Get()->session_controller()->RemoveObserver(this);
  126. }
  127. void NotificationIconsController::AddNotificationTrayItems(
  128. TrayContainer* tray_container) {
  129. for (int i = 0; i < kMaxNotificationIconsShown; ++i) {
  130. tray_items_.push_back(tray_container->AddChildView(
  131. std::make_unique<NotificationIconTrayItemView>(tray_->shelf(), this)));
  132. }
  133. notification_counter_view_ = tray_container->AddChildView(
  134. std::make_unique<NotificationCounterView>(tray_->shelf(), this));
  135. quiet_mode_view_ = tray_container->AddChildView(
  136. std::make_unique<QuietModeView>(tray_->shelf()));
  137. separator_ = tray_container->AddChildView(
  138. std::make_unique<SeparatorTrayItemView>(tray_->shelf()));
  139. OnSystemTrayButtonSizeChanged(tray_->model()->GetSystemTrayButtonSize());
  140. }
  141. bool NotificationIconsController::TrayItemHasNotification() const {
  142. return first_unused_item_index_ != 0;
  143. }
  144. size_t NotificationIconsController::TrayNotificationIconsCount() const {
  145. // `first_unused_item_index_` is also the total number of notification icons
  146. // shown in the tray.
  147. return first_unused_item_index_;
  148. }
  149. std::u16string NotificationIconsController::GetAccessibleNameString() const {
  150. if (!TrayItemHasNotification())
  151. return notification_counter_view_->GetAccessibleNameString();
  152. std::vector<std::u16string> status;
  153. status.push_back(l10n_util::GetPluralStringFUTF16(
  154. IDS_ASH_STATUS_TRAY_NOTIFICATIONS_IMPORTANT_COUNT_ACCESSIBLE_NAME,
  155. TrayNotificationIconsCount()));
  156. for (NotificationIconTrayItemView* tray_item : tray_items_) {
  157. status.push_back(tray_item->GetAccessibleNameString());
  158. }
  159. status.push_back(notification_counter_view_->GetAccessibleNameString());
  160. return l10n_util::GetStringFUTF16(
  161. IDS_ASH_STATUS_TRAY_NOTIFICATIONS_ICONS_ACCESSIBLE_NAME, status, nullptr);
  162. }
  163. void NotificationIconsController::UpdateNotificationIndicators() {
  164. notification_counter_view_->Update();
  165. quiet_mode_view_->Update();
  166. }
  167. void NotificationIconsController::OnSystemTrayButtonSizeChanged(
  168. UnifiedSystemTrayModel::SystemTrayButtonSize system_tray_size) {
  169. icons_view_visible_ =
  170. features::IsScalableStatusAreaEnabled() &&
  171. system_tray_size != UnifiedSystemTrayModel::SystemTrayButtonSize::kSmall;
  172. UpdateNotificationIcons();
  173. UpdateNotificationIndicators();
  174. }
  175. void NotificationIconsController::OnNotificationAdded(const std::string& id) {
  176. message_center::Notification* notification =
  177. message_center::MessageCenter::Get()->FindVisibleNotificationById(id);
  178. // `notification` is null if it is not visible.
  179. if (!notification || !ShouldShowNotification(notification))
  180. return;
  181. // Reset the notification icons if a notification is added since we don't
  182. // know the position where its icon should be added.
  183. UpdateNotificationIcons();
  184. }
  185. void NotificationIconsController::OnNotificationRemoved(const std::string& id,
  186. bool by_user) {
  187. // If the notification removed is displayed in an icon, call update to show
  188. // another notification if needed.
  189. if (GetNotificationIconShownInTray(id))
  190. UpdateNotificationIcons();
  191. }
  192. void NotificationIconsController::OnNotificationUpdated(const std::string& id) {
  193. // A notification update may impact certain notification icon(s) visibility in
  194. // the tray, so update all notification icons.
  195. UpdateNotificationIcons();
  196. }
  197. void NotificationIconsController::OnSessionStateChanged(
  198. session_manager::SessionState state) {
  199. UpdateNotificationIcons();
  200. UpdateNotificationIndicators();
  201. separator_->UpdateColor(state);
  202. }
  203. void NotificationIconsController::UpdateNotificationIcons() {
  204. // Iterates `tray_items_` and notifications in reverse order so new pinned
  205. // notifications get shown on the left side.
  206. auto notifications =
  207. message_center_utils::GetSortedNotificationsWithOwnView();
  208. auto tray_it = tray_items_.rbegin();
  209. for (auto notification_it = notifications.rbegin();
  210. notification_it != notifications.rend(); ++notification_it) {
  211. if (tray_it == tray_items_.rend())
  212. break;
  213. if (ShouldShowNotification(*notification_it)) {
  214. (*tray_it)->SetNotification(*notification_it);
  215. (*tray_it)->SetVisible(icons_view_visible_);
  216. ++tray_it;
  217. }
  218. }
  219. first_unused_item_index_ = std::distance(tray_items_.rbegin(), tray_it);
  220. for (; tray_it != tray_items_.rend(); ++tray_it) {
  221. (*tray_it)->Reset();
  222. (*tray_it)->SetVisible(false);
  223. }
  224. separator_->SetVisible(icons_view_visible_ && TrayItemHasNotification());
  225. }
  226. NotificationIconTrayItemView*
  227. NotificationIconsController::GetNotificationIconShownInTray(
  228. const std::string& id) {
  229. for (NotificationIconTrayItemView* tray_item : tray_items_) {
  230. if (tray_item->GetNotificationId() == id)
  231. return tray_item;
  232. }
  233. return nullptr;
  234. }
  235. } // namespace ash