Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / extensions / settings_api_bubble_controller.cc
blobd5500195165c259e7d0e1fb824f6de06e6312864
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.
5 #include "chrome/browser/extensions/settings_api_bubble_controller.h"
7 #include "base/metrics/histogram.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/settings_api_helpers.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/startup/startup_browser_creator.h"
14 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
15 #include "chrome/common/url_constants.h"
16 #include "chrome/grit/chromium_strings.h"
17 #include "chrome/grit/generated_resources.h"
18 #include "extensions/browser/extension_prefs.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/extension_system.h"
21 #include "grit/components_strings.h"
22 #include "ui/base/l10n/l10n_util.h"
24 namespace extensions {
26 namespace {
28 // Whether the user has been notified about extension taking over some aspect of
29 // the user's settings (homepage, startup pages, or search engine).
30 const char kSettingsBubbleAcknowledged[] = "ack_settings_bubble";
32 ////////////////////////////////////////////////////////////////////////////////
33 // SettingsApiBubbleDelegate
35 class SettingsApiBubbleDelegate
36 : public ExtensionMessageBubbleController::Delegate {
37 public:
38 SettingsApiBubbleDelegate(Profile* profile, SettingsApiOverrideType type);
39 ~SettingsApiBubbleDelegate() override;
41 // ExtensionMessageBubbleController::Delegate methods.
42 bool ShouldIncludeExtension(const std::string& extension_id) override;
43 void AcknowledgeExtension(
44 const std::string& extension_id,
45 ExtensionMessageBubbleController::BubbleAction user_action) override;
46 void PerformAction(const ExtensionIdList& list) override;
47 base::string16 GetTitle() const override;
48 base::string16 GetMessageBody(bool anchored_to_browser_action,
49 int extension_count) const override;
50 base::string16 GetOverflowText(
51 const base::string16& overflow_count) const override;
52 GURL GetLearnMoreUrl() const override;
53 base::string16 GetActionButtonLabel() const override;
54 base::string16 GetDismissButtonLabel() const override;
55 bool ShouldShowExtensionList() const override;
56 bool ShouldHighlightExtensions() const override;
57 void LogExtensionCount(size_t count) override;
58 void LogAction(
59 ExtensionMessageBubbleController::BubbleAction action) override;
61 private:
62 // The type of settings override this bubble will report on. This can be, for
63 // example, a bubble to notify the user that the search engine has been
64 // changed by an extension (or homepage/startup pages/etc).
65 SettingsApiOverrideType type_;
67 // The ID of the extension we are showing the bubble for.
68 std::string extension_id_;
70 DISALLOW_COPY_AND_ASSIGN(SettingsApiBubbleDelegate);
73 SettingsApiBubbleDelegate::SettingsApiBubbleDelegate(
74 Profile* profile,
75 SettingsApiOverrideType type)
76 : ExtensionMessageBubbleController::Delegate(profile),
77 type_(type) {
78 set_acknowledged_flag_pref_name(kSettingsBubbleAcknowledged);
81 SettingsApiBubbleDelegate::~SettingsApiBubbleDelegate() {}
83 bool SettingsApiBubbleDelegate::ShouldIncludeExtension(
84 const std::string& extension_id) {
85 const Extension* extension =
86 registry()->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
87 if (!extension)
88 return false; // The extension provided is no longer enabled.
90 if (HasBubbleInfoBeenAcknowledged(extension_id))
91 return false;
93 const Extension* override = NULL;
94 switch (type_) {
95 case extensions::BUBBLE_TYPE_HOME_PAGE:
96 override = extensions::GetExtensionOverridingHomepage(profile());
97 break;
98 case extensions::BUBBLE_TYPE_STARTUP_PAGES:
99 override = extensions::GetExtensionOverridingStartupPages(profile());
100 break;
101 case extensions::BUBBLE_TYPE_SEARCH_ENGINE:
102 override = extensions::GetExtensionOverridingSearchEngine(profile());
103 break;
106 if (!override || override->id() != extension->id())
107 return false;
109 extension_id_ = extension_id;
110 return true;
113 void SettingsApiBubbleDelegate::AcknowledgeExtension(
114 const std::string& extension_id,
115 ExtensionMessageBubbleController::BubbleAction user_action) {
116 if (user_action != ExtensionMessageBubbleController::ACTION_EXECUTE)
117 SetBubbleInfoBeenAcknowledged(extension_id, true);
120 void SettingsApiBubbleDelegate::PerformAction(const ExtensionIdList& list) {
121 for (size_t i = 0; i < list.size(); ++i) {
122 service()->DisableExtension(list[i], Extension::DISABLE_USER_ACTION);
126 base::string16 SettingsApiBubbleDelegate::GetTitle() const {
127 switch (type_) {
128 case BUBBLE_TYPE_HOME_PAGE:
129 return l10n_util::GetStringUTF16(
130 IDS_EXTENSIONS_SETTINGS_API_TITLE_HOME_PAGE_BUBBLE);
131 case BUBBLE_TYPE_STARTUP_PAGES:
132 return l10n_util::GetStringUTF16(
133 IDS_EXTENSIONS_SETTINGS_API_TITLE_STARTUP_PAGES_BUBBLE);
134 case BUBBLE_TYPE_SEARCH_ENGINE:
135 return l10n_util::GetStringUTF16(
136 IDS_EXTENSIONS_SETTINGS_API_TITLE_SEARCH_ENGINE_BUBBLE);
138 NOTREACHED();
139 return base::string16();
142 base::string16 SettingsApiBubbleDelegate::GetMessageBody(
143 bool anchored_to_browser_action,
144 int extension_count) const {
145 const Extension* extension =
146 registry()->GetExtensionById(extension_id_, ExtensionRegistry::ENABLED);
147 const SettingsOverrides* settings =
148 extension ? SettingsOverrides::Get(extension) : NULL;
149 if (!extension || !settings) {
150 NOTREACHED();
151 return base::string16();
154 bool home_change = settings->homepage != NULL;
155 bool startup_change = !settings->startup_pages.empty();
156 bool search_change = settings->search_engine != NULL;
158 int first_line_id = 0;
159 int second_line_id = 0;
161 base::string16 body;
162 switch (type_) {
163 case BUBBLE_TYPE_HOME_PAGE:
164 first_line_id = anchored_to_browser_action ?
165 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_HOME_PAGE_SPECIFIC :
166 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_HOME_PAGE;
167 if (startup_change && search_change) {
168 second_line_id =
169 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_AND_SEARCH;
170 } else if (startup_change) {
171 second_line_id = IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_PAGES;
172 } else if (search_change) {
173 second_line_id = IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE;
175 break;
176 case BUBBLE_TYPE_STARTUP_PAGES:
177 first_line_id = anchored_to_browser_action ?
178 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_START_PAGES_SPECIFIC :
179 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_START_PAGES;
180 if (home_change && search_change) {
181 second_line_id =
182 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_AND_SEARCH;
183 } else if (home_change) {
184 second_line_id = IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_PAGE;
185 } else if (search_change) {
186 second_line_id = IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE;
188 break;
189 case BUBBLE_TYPE_SEARCH_ENGINE:
190 first_line_id = anchored_to_browser_action ?
191 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_SEARCH_ENGINE_SPECIFIC :
192 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_SEARCH_ENGINE;
193 if (startup_change && home_change)
194 second_line_id = IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_AND_HOME;
195 else if (startup_change)
196 second_line_id = IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_PAGES;
197 else if (home_change)
198 second_line_id = IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_PAGE;
199 break;
201 DCHECK_NE(0, first_line_id);
202 body = anchored_to_browser_action ?
203 l10n_util::GetStringUTF16(first_line_id) :
204 l10n_util::GetStringFUTF16(first_line_id,
205 base::UTF8ToUTF16(extension->name()));
206 if (second_line_id)
207 body += l10n_util::GetStringUTF16(second_line_id);
209 body += l10n_util::GetStringUTF16(
210 IDS_EXTENSIONS_SETTINGS_API_THIRD_LINE_CONFIRMATION);
212 return body;
215 base::string16 SettingsApiBubbleDelegate::GetOverflowText(
216 const base::string16& overflow_count) const {
217 // Does not have more than one extension in the list at a time.
218 NOTREACHED();
219 return base::string16();
222 GURL SettingsApiBubbleDelegate::GetLearnMoreUrl() const {
223 return GURL(chrome::kExtensionControlledSettingLearnMoreURL);
226 base::string16 SettingsApiBubbleDelegate::GetActionButtonLabel() const {
227 return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_RESTORE_SETTINGS);
230 base::string16 SettingsApiBubbleDelegate::GetDismissButtonLabel() const {
231 return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_KEEP_CHANGES);
234 bool SettingsApiBubbleDelegate::ShouldShowExtensionList() const {
235 return false;
238 bool SettingsApiBubbleDelegate::ShouldHighlightExtensions() const {
239 return type_ == BUBBLE_TYPE_STARTUP_PAGES;
242 void SettingsApiBubbleDelegate::LogExtensionCount(size_t count) {
245 void SettingsApiBubbleDelegate::LogAction(
246 ExtensionMessageBubbleController::BubbleAction action) {
247 switch (type_) {
248 case BUBBLE_TYPE_HOME_PAGE:
249 UMA_HISTOGRAM_ENUMERATION(
250 "ExtensionOverrideBubble.SettingsApiUserSelectionHomePage",
251 action,
252 ExtensionMessageBubbleController::ACTION_BOUNDARY);
253 break;
254 case BUBBLE_TYPE_STARTUP_PAGES:
255 UMA_HISTOGRAM_ENUMERATION(
256 "ExtensionOverrideBubble.SettingsApiUserSelectionStartupPage",
257 action,
258 ExtensionMessageBubbleController::ACTION_BOUNDARY);
259 break;
260 case BUBBLE_TYPE_SEARCH_ENGINE:
261 UMA_HISTOGRAM_ENUMERATION(
262 "ExtensionOverrideBubble.SettingsApiUserSelectionSearchEngine",
263 action,
264 ExtensionMessageBubbleController::ACTION_BOUNDARY);
265 break;
269 } // namespace
271 ////////////////////////////////////////////////////////////////////////////////
272 // SettingsApiBubbleController
274 SettingsApiBubbleController::SettingsApiBubbleController(
275 Browser* browser,
276 SettingsApiOverrideType type)
277 : ExtensionMessageBubbleController(
278 new SettingsApiBubbleDelegate(browser->profile(), type),
279 browser),
280 type_(type) {}
282 SettingsApiBubbleController::~SettingsApiBubbleController() {}
284 bool SettingsApiBubbleController::ShouldShow() {
285 const Extension* extension = nullptr;
286 switch (type_) {
287 case BUBBLE_TYPE_HOME_PAGE:
288 extension = GetExtensionOverridingHomepage(profile());
289 break;
290 case BUBBLE_TYPE_SEARCH_ENGINE:
291 extension = GetExtensionOverridingSearchEngine(profile());
292 break;
293 case BUBBLE_TYPE_STARTUP_PAGES:
294 extension = GetExtensionOverridingStartupPages(profile());
295 break;
298 if (!extension)
299 return false;
301 if (delegate()->HasBubbleInfoBeenAcknowledged(extension->id()))
302 return false;
304 if (!delegate()->ShouldIncludeExtension(extension->id()))
305 return false;
307 // If the browser is showing the 'Chrome crashed' infobar, it won't be showing
308 // the startup pages, so there's no point in showing the bubble now.
309 if (type_ == BUBBLE_TYPE_STARTUP_PAGES)
310 return profile()->GetLastSessionExitType() != Profile::EXIT_CRASHED;
312 return true;
315 bool SettingsApiBubbleController::CloseOnDeactivate() {
316 // Startup bubbles tend to get lost in the focus storm that happens on
317 // startup. Other types should dismiss on focus loss.
318 return type_ != BUBBLE_TYPE_STARTUP_PAGES;
321 } // namespace extensions