blob: eadd00d1302388dd72dea2f4e81f4339473d02b7 [file] [log] [blame]
// 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