blob: 428f9727caf1d0877a847e06cb686d33dd8dfd5c [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/public/cpp/ash_features.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller.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 {
// Maximum count of notification shown by a number label. "+" icon is shown
// instead if it exceeds this limit.
constexpr size_t kTrayNotificationMaxCount = 9;
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(20, 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),
false),
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() {
SessionController* session_controller = Shell::Get()->session_controller();
size_t notification_count =
message_center::MessageCenter::Get()->NotificationCount();
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()->set_tooltip_text(l10n_util::GetPluralStringFUTF16(
IDS_ASH_STATUS_TRAY_NOTIFICATIONS_COUNT_TOOLTIP, notification_count));
SetVisible(true);
}
void NotificationCounterView::OnSessionStateChanged(
session_manager::SessionState state) {
Update();
}
QuietModeView::QuietModeView(Shelf* shelf) : TrayItemView(shelf) {
CreateImageView();
image_view()->set_tooltip_text(
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::OnSessionStateChanged(session_manager::SessionState state) {
Update();
}
} // namespace ash