| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/system/unified/notification_counter_view.h" |
| |
| #include <algorithm> |
| |
| #include "ash/media/media_notification_constants.h" |
| #include "ash/public/cpp/ash_features.h" |
| #include "ash/public/cpp/vm_camera_mic_constants.h" |
| #include "ash/resources/vector_icons/vector_icons.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "ash/system/message_center/ash_message_center_lock_screen_controller.h" |
| #include "ash/system/tray/tray_constants.h" |
| #include "ash/system/tray/tray_utils.h" |
| #include "base/i18n/number_formatting.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/font_list.h" |
| #include "ui/gfx/image/canvas_image_source.h" |
| #include "ui/message_center/message_center.h" |
| #include "ui/views/controls/image_view.h" |
| #include "ui/views/controls/label.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| constexpr double kTrayNotificationCircleIconRadius = 8; |
| |
| // The size of the number font inside the icon. Should be updated when |
| // kUnifiedTrayIconSize is changed. |
| constexpr int kNumberIconFontSize = 11; |
| |
| gfx::FontList GetNumberIconFontList() { |
| // |kNumberIconFontSize| is hard-coded as 11, which whould be updated when |
| // the tray icon size is changed. |
| DCHECK_EQ(18, kUnifiedTrayIconSize); |
| |
| gfx::Font default_font; |
| int font_size_delta = kNumberIconFontSize - default_font.GetFontSize(); |
| gfx::Font font = default_font.Derive(font_size_delta, gfx::Font::NORMAL, |
| gfx::Font::Weight::BOLD); |
| DCHECK_EQ(kNumberIconFontSize, font.GetFontSize()); |
| return gfx::FontList(font); |
| } |
| |
| class NumberIconImageSource : public gfx::CanvasImageSource { |
| public: |
| explicit NumberIconImageSource(size_t count) |
| : CanvasImageSource( |
| gfx::Size(kUnifiedTrayIconSize, kUnifiedTrayIconSize)), |
| count_(count) { |
| DCHECK_LE(count_, kTrayNotificationMaxCount + 1); |
| } |
| |
| void Draw(gfx::Canvas* canvas) override { |
| SkColor tray_icon_color = |
| TrayIconColor(Shell::Get()->session_controller()->GetSessionState()); |
| // Paint the contents inside the circle background. The color doesn't matter |
| // as it will be hollowed out by the XOR operation. |
| if (count_ > kTrayNotificationMaxCount) { |
| canvas->DrawImageInt( |
| gfx::CreateVectorIcon(kSystemTrayNotificationCounterPlusIcon, |
| size().width(), tray_icon_color), |
| 0, 0); |
| } else { |
| canvas->DrawStringRectWithFlags( |
| base::FormatNumber(count_), GetNumberIconFontList(), tray_icon_color, |
| gfx::Rect(size()), |
| gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_SUBPIXEL_RENDERING); |
| } |
| cc::PaintFlags flags; |
| flags.setBlendMode(SkBlendMode::kXor); |
| flags.setAntiAlias(true); |
| flags.setColor(tray_icon_color); |
| canvas->DrawCircle(gfx::RectF(gfx::SizeF(size())).CenterPoint(), |
| kTrayNotificationCircleIconRadius, flags); |
| } |
| |
| private: |
| size_t count_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NumberIconImageSource); |
| }; |
| |
| } // namespace |
| |
| NotificationCounterView::NotificationCounterView(Shelf* shelf) |
| : TrayItemView(shelf) { |
| CreateImageView(); |
| SetVisible(false); |
| Shell::Get()->session_controller()->AddObserver(this); |
| } |
| |
| NotificationCounterView::~NotificationCounterView() { |
| Shell::Get()->session_controller()->RemoveObserver(this); |
| } |
| |
| void NotificationCounterView::Update() { |
| SessionControllerImpl* session_controller = |
| Shell::Get()->session_controller(); |
| |
| // If flag is set, do not include media notifications in count. |
| // TODO(crbug.com/1111881) This code can be removed when OS media controls are |
| // launched (expected by M90). |
| const bool dont_count_media_notification = |
| base::FeatureList::IsEnabled(features::kMediaNotificationsCounter); |
| |
| const message_center::NotificationList::Notifications& visible = |
| message_center::MessageCenter::Get()->GetVisibleNotifications(); |
| |
| size_t notification_count = std::count_if( |
| visible.begin(), visible.end(), |
| [dont_count_media_notification]( |
| message_center::Notification* notification) { |
| const std::string& notifier = notification->notifier_id().id; |
| // Don't count these notifications since we have `CameraMicTrayItemView` |
| // to show indicators on the systray. |
| if (notifier == kVmCameraMicNotifierId) { |
| return false; |
| } |
| if (dont_count_media_notification && |
| notifier == kMediaSessionNotifierId) { |
| return false; |
| } |
| return true; |
| }); |
| |
| if (notification_count == 0 || |
| message_center::MessageCenter::Get()->IsQuietMode() || |
| !session_controller->ShouldShowNotificationTray() || |
| (session_controller->IsScreenLocked() && |
| !AshMessageCenterLockScreenController::IsEnabled())) { |
| SetVisible(false); |
| return; |
| } |
| int icon_id = std::min(notification_count, kTrayNotificationMaxCount + 1); |
| if (icon_id != count_for_display_) { |
| image_view()->SetImage( |
| gfx::CanvasImageSource::MakeImageSkia<NumberIconImageSource>(icon_id)); |
| count_for_display_ = icon_id; |
| } |
| image_view()->SetTooltipText(l10n_util::GetPluralStringFUTF16( |
| IDS_ASH_STATUS_TRAY_NOTIFICATIONS_COUNT_TOOLTIP, notification_count)); |
| SetVisible(true); |
| } |
| |
| base::string16 NotificationCounterView::GetAccessibleNameString() const { |
| return l10n_util::GetPluralStringFUTF16( |
| IDS_ASH_STATUS_TRAY_NOTIFICATIONS_COUNT_TOOLTIP, |
| message_center::MessageCenter::Get()->NotificationCount()); |
| } |
| |
| void NotificationCounterView::HandleLocaleChange() { |
| Update(); |
| } |
| |
| void NotificationCounterView::OnSessionStateChanged( |
| session_manager::SessionState state) { |
| Update(); |
| } |
| |
| const char* NotificationCounterView::GetClassName() const { |
| return "NotificationCounterView"; |
| } |
| |
| QuietModeView::QuietModeView(Shelf* shelf) : TrayItemView(shelf) { |
| CreateImageView(); |
| image_view()->SetTooltipText( |
| l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_QUIET_MODE_TOOLTIP)); |
| SetVisible(false); |
| Shell::Get()->session_controller()->AddObserver(this); |
| } |
| |
| QuietModeView::~QuietModeView() { |
| Shell::Get()->session_controller()->RemoveObserver(this); |
| } |
| |
| void QuietModeView::Update() { |
| // TODO(yamaguchi): Add this check when new style of the system tray is |
| // implemented, so that icon resizing will not happen here. |
| // DCHECK_EQ(kTrayIconSize, |
| // gfx::GetDefaultSizeOfVectorIcon(kSystemTrayDoNotDisturbIcon)); |
| if (message_center::MessageCenter::Get()->IsQuietMode()) { |
| image_view()->SetImage(gfx::CreateVectorIcon( |
| kSystemTrayDoNotDisturbIcon, |
| TrayIconColor(Shell::Get()->session_controller()->GetSessionState()))); |
| SetVisible(true); |
| } else { |
| SetVisible(false); |
| } |
| } |
| |
| void QuietModeView::HandleLocaleChange() { |
| image_view()->SetTooltipText( |
| l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_QUIET_MODE_TOOLTIP)); |
| } |
| |
| void QuietModeView::OnSessionStateChanged(session_manager::SessionState state) { |
| Update(); |
| } |
| |
| const char* QuietModeView::GetClassName() const { |
| return "QuietModeView"; |
| } |
| |
| } // namespace ash |