1 // Copyright (c) 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 "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/extension_toolbar_model.h"
10 #include "chrome/browser/extensions/settings_api_helpers.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/startup/startup_browser_creator.h"
13 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
14 #include "chrome/common/url_constants.h"
15 #include "chrome/grit/chromium_strings.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "extensions/browser/extension_prefs.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "extensions/browser/extension_system.h"
20 #include "grit/components_strings.h"
21 #include "ui/base/l10n/l10n_util.h"
23 namespace extensions {
27 ////////////////////////////////////////////////////////////////////////////////
28 // SettingsApiBubbleDelegate
30 class SettingsApiBubbleDelegate
31 : public ExtensionMessageBubbleController::Delegate {
33 explicit SettingsApiBubbleDelegate(ExtensionService* service,
35 SettingsApiOverrideType type);
36 virtual ~SettingsApiBubbleDelegate();
38 // ExtensionMessageBubbleController::Delegate methods.
39 virtual bool ShouldIncludeExtension(const std::string& extension_id) OVERRIDE;
40 virtual void AcknowledgeExtension(
41 const std::string& extension_id,
42 ExtensionMessageBubbleController::BubbleAction user_action) OVERRIDE;
43 virtual void PerformAction(const ExtensionIdList& list) OVERRIDE;
44 virtual void OnClose() OVERRIDE;
45 virtual base::string16 GetTitle() const OVERRIDE;
46 virtual base::string16 GetMessageBody(
47 bool anchored_to_browser_action) const OVERRIDE;
48 virtual base::string16 GetOverflowText(
49 const base::string16& overflow_count) const OVERRIDE;
50 virtual base::string16 GetLearnMoreLabel() const OVERRIDE;
51 virtual GURL GetLearnMoreUrl() const OVERRIDE;
52 virtual base::string16 GetActionButtonLabel() const OVERRIDE;
53 virtual base::string16 GetDismissButtonLabel() const OVERRIDE;
54 virtual bool ShouldShowExtensionList() const OVERRIDE;
55 virtual void LogExtensionCount(size_t count) OVERRIDE;
56 virtual void LogAction(
57 ExtensionMessageBubbleController::BubbleAction action) OVERRIDE;
60 // Our extension service. Weak, not owned by us.
61 ExtensionService* service_;
63 // A weak pointer to the profile we are associated with. Not owned by us.
66 // The type of settings override this bubble will report on. This can be, for
67 // example, a bubble to notify the user that the search engine has been
68 // changed by an extension (or homepage/startup pages/etc).
69 SettingsApiOverrideType type_;
71 // The ID of the extension we are showing the bubble for.
72 std::string extension_id_;
74 DISALLOW_COPY_AND_ASSIGN(SettingsApiBubbleDelegate);
77 SettingsApiBubbleDelegate::SettingsApiBubbleDelegate(
78 ExtensionService* service,
80 SettingsApiOverrideType type)
81 : service_(service), profile_(profile), type_(type) {}
83 SettingsApiBubbleDelegate::~SettingsApiBubbleDelegate() {}
85 bool SettingsApiBubbleDelegate::ShouldIncludeExtension(
86 const std::string& extension_id) {
87 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
88 const Extension* extension =
89 registry->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
91 return false; // The extension provided is no longer enabled.
93 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
94 if (prefs->HasSettingsApiBubbleBeenAcknowledged(extension_id))
97 const Extension* override = NULL;
99 case extensions::BUBBLE_TYPE_HOME_PAGE:
100 override = extensions::GetExtensionOverridingHomepage(profile_);
102 case extensions::BUBBLE_TYPE_STARTUP_PAGES:
103 override = extensions::GetExtensionOverridingStartupPages(profile_);
105 case extensions::BUBBLE_TYPE_SEARCH_ENGINE:
106 override = extensions::GetExtensionOverridingSearchEngine(profile_);
110 if (!override || override->id() != extension->id())
113 extension_id_ = extension_id;
117 void SettingsApiBubbleDelegate::AcknowledgeExtension(
118 const std::string& extension_id,
119 ExtensionMessageBubbleController::BubbleAction user_action) {
120 if (user_action != ExtensionMessageBubbleController::ACTION_EXECUTE) {
121 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
122 prefs->SetSettingsApiBubbleBeenAcknowledged(extension_id, true);
126 void SettingsApiBubbleDelegate::PerformAction(const ExtensionIdList& list) {
127 for (size_t i = 0; i < list.size(); ++i) {
128 service_->DisableExtension(list[i], Extension::DISABLE_USER_ACTION);
132 void SettingsApiBubbleDelegate::OnClose() {
133 ExtensionToolbarModel* toolbar_model = ExtensionToolbarModel::Get(profile_);
135 toolbar_model->StopHighlighting();
138 base::string16 SettingsApiBubbleDelegate::GetTitle() const {
140 case BUBBLE_TYPE_HOME_PAGE:
141 return l10n_util::GetStringUTF16(
142 IDS_EXTENSIONS_SETTINGS_API_TITLE_HOME_PAGE_BUBBLE);
143 case BUBBLE_TYPE_STARTUP_PAGES:
144 return l10n_util::GetStringUTF16(
145 IDS_EXTENSIONS_SETTINGS_API_TITLE_STARTUP_PAGES_BUBBLE);
146 case BUBBLE_TYPE_SEARCH_ENGINE:
147 return l10n_util::GetStringUTF16(
148 IDS_EXTENSIONS_SETTINGS_API_TITLE_SEARCH_ENGINE_BUBBLE);
151 return base::string16();
154 base::string16 SettingsApiBubbleDelegate::GetMessageBody(
155 bool anchored_to_browser_action) const {
156 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
157 const Extension* extension =
158 registry->GetExtensionById(extension_id_, ExtensionRegistry::ENABLED);
159 const SettingsOverrides* settings =
160 extension ? SettingsOverrides::Get(extension) : NULL;
161 if (!extension || !settings) {
163 return base::string16();
166 bool home_change = settings->homepage != NULL;
167 bool startup_change = !settings->startup_pages.empty();
168 bool search_change = settings->search_engine != NULL;
172 case BUBBLE_TYPE_HOME_PAGE:
173 body = l10n_util::GetStringUTF16(
174 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_HOME_PAGE);
175 if (startup_change && search_change) {
176 body += l10n_util::GetStringUTF16(
177 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_AND_SEARCH);
178 } else if (startup_change) {
179 body += l10n_util::GetStringUTF16(
180 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_PAGES);
181 } else if (search_change) {
182 body += l10n_util::GetStringUTF16(
183 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE);
186 case BUBBLE_TYPE_STARTUP_PAGES:
187 body = l10n_util::GetStringUTF16(
188 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_START_PAGES);
189 if (home_change && search_change) {
190 body += l10n_util::GetStringUTF16(
191 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_AND_SEARCH);
192 } else if (home_change) {
193 body += l10n_util::GetStringUTF16(
194 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_PAGE);
195 } else if (search_change) {
196 body += l10n_util::GetStringUTF16(
197 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE);
200 case BUBBLE_TYPE_SEARCH_ENGINE:
201 body = l10n_util::GetStringUTF16(
202 IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_SEARCH_ENGINE);
203 if (startup_change && home_change) {
204 body += l10n_util::GetStringUTF16(
205 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_AND_HOME);
206 } else if (startup_change) {
207 body += l10n_util::GetStringUTF16(
208 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_START_PAGES);
209 } else if (home_change) {
210 body += l10n_util::GetStringUTF16(
211 IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_HOME_PAGE);
216 body += l10n_util::GetStringUTF16(
217 IDS_EXTENSIONS_SETTINGS_API_THIRD_LINE_CONFIRMATION);
221 base::string16 SettingsApiBubbleDelegate::GetOverflowText(
222 const base::string16& overflow_count) const {
223 // Does not have more than one extension in the list at a time.
225 return base::string16();
228 base::string16 SettingsApiBubbleDelegate::GetLearnMoreLabel() const {
229 return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
232 GURL SettingsApiBubbleDelegate::GetLearnMoreUrl() const {
233 return GURL(chrome::kExtensionControlledSettingLearnMoreURL);
236 base::string16 SettingsApiBubbleDelegate::GetActionButtonLabel() const {
237 return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_RESTORE_SETTINGS);
240 base::string16 SettingsApiBubbleDelegate::GetDismissButtonLabel() const {
241 return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_KEEP_CHANGES);
244 bool SettingsApiBubbleDelegate::ShouldShowExtensionList() const {
248 void SettingsApiBubbleDelegate::LogExtensionCount(size_t count) {
251 void SettingsApiBubbleDelegate::LogAction(
252 ExtensionMessageBubbleController::BubbleAction action) {
254 case BUBBLE_TYPE_HOME_PAGE:
255 UMA_HISTOGRAM_ENUMERATION(
256 "ExtensionOverrideBubble.SettingsApiUserSelectionHomePage",
258 ExtensionMessageBubbleController::ACTION_BOUNDARY);
260 case BUBBLE_TYPE_STARTUP_PAGES:
261 UMA_HISTOGRAM_ENUMERATION(
262 "ExtensionOverrideBubble.SettingsApiUserSelectionStartupPage",
264 ExtensionMessageBubbleController::ACTION_BOUNDARY);
266 case BUBBLE_TYPE_SEARCH_ENGINE:
267 UMA_HISTOGRAM_ENUMERATION(
268 "ExtensionOverrideBubble.SettingsApiUserSelectionSearchEngine",
270 ExtensionMessageBubbleController::ACTION_BOUNDARY);
277 ////////////////////////////////////////////////////////////////////////////////
278 // SettingsApiBubbleController
280 SettingsApiBubbleController::SettingsApiBubbleController(
282 SettingsApiOverrideType type)
283 : ExtensionMessageBubbleController(
284 new SettingsApiBubbleDelegate(
285 ExtensionSystem::Get(profile)->extension_service(),
292 SettingsApiBubbleController::~SettingsApiBubbleController() {}
294 bool SettingsApiBubbleController::ShouldShow(const std::string& extension_id) {
295 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
296 if (prefs->HasSettingsApiBubbleBeenAcknowledged(extension_id))
299 if (!delegate()->ShouldIncludeExtension(extension_id))
302 // If the browser is showing the 'Chrome crashed' infobar, it won't be showing
303 // the startup pages, so there's no point in showing the bubble now.
304 if (type_ == BUBBLE_TYPE_STARTUP_PAGES)
305 return profile_->GetLastSessionExitType() != Profile::EXIT_CRASHED;
310 bool SettingsApiBubbleController::CloseOnDeactivate() {
311 // Startup bubbles tend to get lost in the focus storm that happens on
312 // startup. Other types should dismiss on focus loss.
313 return type_ != BUBBLE_TYPE_STARTUP_PAGES;
316 } // namespace extensions