1 // Copyright (c) 2012 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/extensions/warning_badge_service.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 
11 #include "base/stl_util.h"
12 #include "chrome/app/chrome_command_ids.h"
13 #include "chrome/browser/extensions/warning_badge_service_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser_commands.h"
16 #include "chrome/browser/ui/global_error/global_error.h"
17 #include "chrome/browser/ui/global_error/global_error_service.h"
18 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "ui/base/l10n/l10n_util.h"
22 
23 namespace extensions {
24 
25 namespace {
26 // Non-modal GlobalError implementation that warns the user if extensions
27 // created warnings or errors. If the user clicks on the wrench menu, the user
28 // is redirected to chrome://extensions to inspect the errors.
29 class ErrorBadge : public GlobalError {
30  public:
31   explicit ErrorBadge(WarningBadgeService* badge_service);
32   ErrorBadge(const ErrorBadge&) = delete;
33   ErrorBadge& operator=(const ErrorBadge&) = delete;
34   ~ErrorBadge() override;
35 
36   // Implementation for GlobalError:
37   bool HasMenuItem() override;
38   int MenuItemCommandID() override;
39   base::string16 MenuItemLabel() override;
40   void ExecuteMenuItem(Browser* browser) override;
41 
42   bool HasBubbleView() override;
43   bool HasShownBubbleView() override;
44   void ShowBubbleView(Browser* browser) override;
45   GlobalErrorBubbleViewBase* GetBubbleView() override;
46 
47   static int GetMenuItemCommandID();
48 
49  private:
50   WarningBadgeService* badge_service_;
51 };
52 
ErrorBadge(WarningBadgeService * badge_service)53 ErrorBadge::ErrorBadge(WarningBadgeService* badge_service)
54     : badge_service_(badge_service) {
55 }
56 
~ErrorBadge()57 ErrorBadge::~ErrorBadge() {
58 }
59 
HasMenuItem()60 bool ErrorBadge::HasMenuItem() {
61   return true;
62 }
63 
MenuItemCommandID()64 int ErrorBadge::MenuItemCommandID() {
65   return GetMenuItemCommandID();
66 }
67 
MenuItemLabel()68 base::string16 ErrorBadge::MenuItemLabel() {
69   return l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_WRENCH_MENU_ITEM);
70 }
71 
ExecuteMenuItem(Browser * browser)72 void ErrorBadge::ExecuteMenuItem(Browser* browser) {
73   // Suppress all current warnings in the extension service from triggering
74   // a badge on the wrench menu in the future of this session.
75   badge_service_->SuppressCurrentWarnings();
76 
77   chrome::ExecuteCommand(browser, IDC_MANAGE_EXTENSIONS);
78 }
79 
HasBubbleView()80 bool ErrorBadge::HasBubbleView() {
81   return false;
82 }
83 
HasShownBubbleView()84 bool ErrorBadge::HasShownBubbleView() {
85   return false;
86 }
87 
ShowBubbleView(Browser * browser)88 void ErrorBadge::ShowBubbleView(Browser* browser) {
89   NOTREACHED();
90 }
91 
GetBubbleView()92 GlobalErrorBubbleViewBase* ErrorBadge::GetBubbleView() {
93   return NULL;
94 }
95 
96 // static
GetMenuItemCommandID()97 int ErrorBadge::GetMenuItemCommandID() {
98   return IDC_EXTENSION_ERRORS;
99 }
100 
101 }  // namespace
102 
WarningBadgeService(Profile * profile)103 WarningBadgeService::WarningBadgeService(Profile* profile)
104     : profile_(profile), warning_service_observer_(this) {
105   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
106   warning_service_observer_.Add(WarningService::Get(profile_));
107 }
108 
~WarningBadgeService()109 WarningBadgeService::~WarningBadgeService() {
110   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
111 }
112 
113 // static
Get(content::BrowserContext * context)114 WarningBadgeService* WarningBadgeService::Get(
115     content::BrowserContext* context) {
116   return WarningBadgeServiceFactory::GetForBrowserContext(context);
117 }
118 
SuppressCurrentWarnings()119 void WarningBadgeService::SuppressCurrentWarnings() {
120   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
121   size_t old_size = suppressed_warnings_.size();
122 
123   const WarningSet& warnings = GetCurrentWarnings();
124   suppressed_warnings_.insert(warnings.begin(), warnings.end());
125 
126   if (old_size != suppressed_warnings_.size())
127     UpdateBadgeStatus();
128 }
129 
GetCurrentWarnings() const130 const WarningSet& WarningBadgeService::GetCurrentWarnings() const {
131   return WarningService::Get(profile_)->warnings();
132 }
133 
ExtensionWarningsChanged(const ExtensionIdSet & affected_extensions)134 void WarningBadgeService::ExtensionWarningsChanged(
135     const ExtensionIdSet& affected_extensions) {
136   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
137   UpdateBadgeStatus();
138 }
139 
UpdateBadgeStatus()140 void WarningBadgeService::UpdateBadgeStatus() {
141   const std::set<Warning>& warnings = GetCurrentWarnings();
142   bool non_suppressed_warnings_exist = false;
143   for (auto i = warnings.begin(); i != warnings.end(); ++i) {
144     if (!base::Contains(suppressed_warnings_, *i)) {
145       non_suppressed_warnings_exist = true;
146       break;
147     }
148   }
149   ShowBadge(non_suppressed_warnings_exist);
150 }
151 
ShowBadge(bool show)152 void WarningBadgeService::ShowBadge(bool show) {
153   GlobalErrorService* service =
154       GlobalErrorServiceFactory::GetForProfile(profile_);
155   GlobalError* error = service->GetGlobalErrorByMenuItemCommandID(
156       ErrorBadge::GetMenuItemCommandID());
157 
158   // Activate or hide the warning badge in case the current state is incorrect.
159   if (error && !show)
160     service->RemoveGlobalError(error);
161   else if (!error && show)
162     service->AddGlobalError(std::make_unique<ErrorBadge>(this));
163 }
164 
165 }  // namespace extensions
166