1// Copyright 2014 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
5#include "chrome/browser/ui/toolbar/wrench_menu_badge_controller.h"
6
7#include "base/logging.h"
8#include "chrome/browser/chrome_notification_types.h"
9#include "chrome/browser/ui/global_error/global_error_service.h"
10#include "chrome/browser/ui/global_error/global_error_service_factory.h"
11#include "chrome/browser/upgrade_detector.h"
12
13#if defined(OS_WIN)
14#include "base/win/windows_version.h"
15#include "chrome/browser/enumerate_modules_model_win.h"
16#endif
17
18namespace {
19
20// Maps an upgrade level to a severity level.
21WrenchIconPainter::Severity SeverityFromUpgradeLevel(
22    UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
23  switch (level) {
24    case UpgradeDetector::UPGRADE_ANNOYANCE_NONE:
25      return WrenchIconPainter::SEVERITY_NONE;
26    case UpgradeDetector::UPGRADE_ANNOYANCE_LOW:
27      return WrenchIconPainter::SEVERITY_LOW;
28    case UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED:
29      return WrenchIconPainter::SEVERITY_MEDIUM;
30    case UpgradeDetector::UPGRADE_ANNOYANCE_HIGH:
31      return WrenchIconPainter::SEVERITY_HIGH;
32    case UpgradeDetector::UPGRADE_ANNOYANCE_SEVERE:
33      return WrenchIconPainter::SEVERITY_HIGH;
34    case UpgradeDetector::UPGRADE_ANNOYANCE_CRITICAL:
35      return WrenchIconPainter::SEVERITY_HIGH;
36  }
37  NOTREACHED();
38  return WrenchIconPainter::SEVERITY_NONE;
39}
40
41// Checks if the wrench icon should be animated for the given upgrade level.
42bool ShouldAnimateUpgradeLevel(
43    UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
44  bool should_animate = true;
45  if (level == UpgradeDetector::UPGRADE_ANNOYANCE_LOW) {
46    // Only animate low severity upgrades once.
47    static bool should_animate_low_severity = true;
48    should_animate = should_animate_low_severity;
49    should_animate_low_severity = false;
50  }
51  return should_animate;
52}
53
54// Returns true if we should show the upgrade recommended badge.
55bool ShouldShowUpgradeRecommended() {
56#if defined(OS_CHROMEOS)
57  // In chromeos, the update recommendation is shown in the system tray. So it
58  // should not be displayed in the wrench menu.
59  return false;
60#else
61  return UpgradeDetector::GetInstance()->notify_upgrade();
62#endif
63}
64
65// Returns true if we should show the warning for incompatible software.
66bool ShouldShowIncompatibilityWarning() {
67#if defined(OS_WIN)
68  EnumerateModulesModel* loaded_modules = EnumerateModulesModel::GetInstance();
69  loaded_modules->MaybePostScanningTask();
70  return loaded_modules->ShouldShowConflictWarning();
71#else
72  return false;
73#endif
74}
75
76}  // namespace
77
78WrenchMenuBadgeController::WrenchMenuBadgeController(Profile* profile,
79                                                     Delegate* delegate)
80    : profile_(profile), delegate_(delegate) {
81  DCHECK(profile_);
82  DCHECK(delegate_);
83
84  registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
85                 content::NotificationService::AllSources());
86  registrar_.Add(this, chrome::NOTIFICATION_GLOBAL_ERRORS_CHANGED,
87                 content::Source<Profile>(profile_));
88
89#if defined(OS_WIN)
90  if (base::win::GetVersion() == base::win::VERSION_XP) {
91    registrar_.Add(this, chrome::NOTIFICATION_MODULE_LIST_ENUMERATED,
92                   content::NotificationService::AllSources());
93  }
94  registrar_.Add(this, chrome::NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE,
95                 content::NotificationService::AllSources());
96#endif
97}
98
99WrenchMenuBadgeController::~WrenchMenuBadgeController() {
100}
101
102void WrenchMenuBadgeController::UpdateDelegate() {
103  if (ShouldShowUpgradeRecommended()) {
104    UpgradeDetector::UpgradeNotificationAnnoyanceLevel level =
105        UpgradeDetector::GetInstance()->upgrade_notification_stage();
106    delegate_->UpdateBadgeSeverity(BADGE_TYPE_UPGRADE_NOTIFICATION,
107                                   SeverityFromUpgradeLevel(level),
108                                   ShouldAnimateUpgradeLevel(level));
109    return;
110  }
111
112  if (ShouldShowIncompatibilityWarning()) {
113    delegate_->UpdateBadgeSeverity(BADGE_TYPE_INCOMPATIBILITY_WARNING,
114                                   WrenchIconPainter::SEVERITY_MEDIUM, true);
115    return;
116  }
117
118  if (GlobalErrorServiceFactory::GetForProfile(profile_)->
119          GetHighestSeverityGlobalErrorWithWrenchMenuItem()) {
120    // If you change the severity here, make sure to also change the menu icon
121    // and the bubble icon.
122    delegate_->UpdateBadgeSeverity(BADGE_TYPE_GLOBAL_ERROR,
123                                   WrenchIconPainter::SEVERITY_MEDIUM, true);
124    return;
125  }
126
127  delegate_->UpdateBadgeSeverity(BADGE_TYPE_NONE,
128                                 WrenchIconPainter::SEVERITY_NONE, true);
129}
130
131void WrenchMenuBadgeController::Observe(
132    int type,
133    const content::NotificationSource& source,
134    const content::NotificationDetails& details) {
135  UpdateDelegate();
136}
137