blob: a455f0afcc34782b5746721b1a3996e19b1e8412 [file] [log] [blame]
// Copyright 2014 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 "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
#include "base/logging.h"
#include "build/build_config.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/global_error/global_error_service.h"
#include "chrome/browser/ui/global_error/global_error_service_factory.h"
#include "chrome/browser/upgrade_detector/upgrade_detector.h"
#include "chrome/common/channel_info.h"
#include "components/version_info/channel.h"
#include "ui/base/theme_provider.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/native_theme/native_theme.h"
namespace {
// Maps an upgrade level to a severity level. When |show_very_low_upgrade_level|
// is true, VERY_LOW through HIGH all return Severity::LOW. Otherwise, VERY_LOW
// is ignored and LOW through HIGH return their respective Severity level.
AppMenuIconController::Severity SeverityFromUpgradeLevel(
bool show_very_low_upgrade_level,
UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
if (show_very_low_upgrade_level) {
// Anything between kNone and kCritical is LOW for unstable desktop Chrome.
switch (level) {
case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
break;
case UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW:
case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
return AppMenuIconController::Severity::LOW;
case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
return AppMenuIconController::Severity::HIGH;
}
} else {
switch (level) {
case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
break;
case UpgradeDetector::UPGRADE_ANNOYANCE_VERY_LOW:
// kVeryLow is meaningless for stable channels.
return AppMenuIconController::Severity::NONE;
case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
return AppMenuIconController::Severity::LOW;
case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
return AppMenuIconController::Severity::MEDIUM;
case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
return AppMenuIconController::Severity::HIGH;
}
}
DCHECK_EQ(level, UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
return AppMenuIconController::Severity::NONE;
}
// Return true if the browser is updating on the dev or canary channels.
bool IsUnstableChannel() {
// Unbranded (Chromium) builds are on the UNKNOWN channel, so check explicitly
// for the Google Chrome channels that are considered "unstable". This ensures
// that Chromium builds get the default behavior.
const version_info::Channel channel = chrome::GetChannel();
return channel == version_info::Channel::DEV ||
channel == version_info::Channel::CANARY;
}
// Returns the icon color based on |severity|. |promo_highlight_color|, if
// specified, overrides the basic color when |severity| is NONE.
SkColor GetIconColorForSeverity(AppMenuIconController::Delegate* delegate,
AppMenuIconController::Severity severity,
base::Optional<SkColor> promo_highlight_color) {
ui::NativeTheme::ColorId color_id =
ui::NativeTheme::kColorId_AlertSeverityHigh;
switch (severity) {
case AppMenuIconController::Severity::NONE:
if (promo_highlight_color)
return promo_highlight_color.value();
return delegate->GetViewThemeProvider()->GetColor(
ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
case AppMenuIconController::Severity::LOW:
color_id = ui::NativeTheme::kColorId_AlertSeverityLow;
break;
case AppMenuIconController::Severity::MEDIUM:
color_id = ui::NativeTheme::kColorId_AlertSeverityMedium;
break;
case AppMenuIconController::Severity::HIGH:
break;
}
return delegate->GetViewNativeTheme()->GetSystemColor(color_id);
}
} // namespace
AppMenuIconController::AppMenuIconController(Profile* profile,
Delegate* delegate)
: AppMenuIconController(UpgradeDetector::GetInstance(), profile, delegate) {
}
AppMenuIconController::AppMenuIconController(UpgradeDetector* upgrade_detector,
Profile* profile,
Delegate* delegate)
: is_unstable_channel_(IsUnstableChannel()),
upgrade_detector_(upgrade_detector),
profile_(profile),
delegate_(delegate) {
DCHECK(profile_);
DCHECK(delegate_);
registrar_.Add(this, chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED,
content::Source<Profile>(profile_));
upgrade_detector_->AddObserver(this);
}
AppMenuIconController::~AppMenuIconController() {
upgrade_detector_->RemoveObserver(this);
}
void AppMenuIconController::UpdateDelegate() {
delegate_->UpdateTypeAndSeverity(GetTypeAndSeverity());
}
AppMenuIconController::TypeAndSeverity
AppMenuIconController::GetTypeAndSeverity() const {
if (browser_defaults::kShowUpgradeMenuItem &&
upgrade_detector_->notify_upgrade()) {
UpgradeDetector::UpgradeNotificationAnnoyanceLevel level =
upgrade_detector_->upgrade_notification_stage();
// The severity may be NONE even if the detector has been notified of an
// update. This can happen for beta and stable channels once the VERY_LOW
// annoyance level is reached.
auto severity = SeverityFromUpgradeLevel(is_unstable_channel_, level);
if (severity != Severity::NONE)
return {IconType::UPGRADE_NOTIFICATION, severity};
}
if (GlobalErrorServiceFactory::GetForProfile(profile_)
->GetHighestSeverityGlobalErrorWithAppMenuItem()) {
// If you change the severity here, make sure to also change the menu icon
// and the bubble icon.
return {IconType::GLOBAL_ERROR, Severity::MEDIUM};
}
return {IconType::NONE, Severity::NONE};
}
gfx::ImageSkia AppMenuIconController::GetIconImage(
bool touch_ui,
base::Optional<SkColor> promo_highlight_color) const {
const auto type_and_severity = GetTypeAndSeverity();
const gfx::VectorIcon* icon_id =
touch_ui ? &kBrowserToolsTouchIcon : &kBrowserToolsIcon;
switch (type_and_severity.type) {
case AppMenuIconController::IconType::NONE:
break;
case AppMenuIconController::IconType::UPGRADE_NOTIFICATION:
icon_id =
touch_ui ? &kBrowserToolsUpdateTouchIcon : &kBrowserToolsUpdateIcon;
break;
case AppMenuIconController::IconType::GLOBAL_ERROR:
icon_id =
touch_ui ? &kBrowserToolsErrorTouchIcon : &kBrowserToolsErrorIcon;
break;
}
return gfx::CreateVectorIcon(
*icon_id, GetIconColorForSeverity(delegate_, type_and_severity.severity,
promo_highlight_color));
}
void AppMenuIconController::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED, type);
UpdateDelegate();
}
void AppMenuIconController::OnUpgradeRecommended() {
UpdateDelegate();
}