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/extensions/proxy_overridden_bubble_controller.h"
6
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/common/url_constants.h"
13#include "chrome/grit/generated_resources.h"
14#include "extensions/browser/extension_registry.h"
15#include "extensions/browser/extension_system.h"
16#include "grit/components_strings.h"
17#include "ui/base/l10n/l10n_util.h"
18
19namespace extensions {
20
21namespace {
22
23// The minimum time to wait (since the extension was installed) before notifying
24// the user about it.
25const int kDaysSinceInstallMin = 7;
26
27////////////////////////////////////////////////////////////////////////////////
28// ProxyOverriddenBubbleDelegate
29
30class ProxyOverriddenBubbleDelegate
31    : public ExtensionMessageBubbleController::Delegate {
32 public:
33  ProxyOverriddenBubbleDelegate(ExtensionService* service, Profile* profile);
34  virtual ~ProxyOverriddenBubbleDelegate();
35
36  // ExtensionMessageBubbleController::Delegate methods.
37  virtual bool ShouldIncludeExtension(const std::string& extension_id) OVERRIDE;
38  virtual void AcknowledgeExtension(
39      const std::string& extension_id,
40      ExtensionMessageBubbleController::BubbleAction
41          user_action) OVERRIDE;
42  virtual void PerformAction(const ExtensionIdList& list) OVERRIDE;
43  virtual void OnClose() OVERRIDE;
44  virtual base::string16 GetTitle() const OVERRIDE;
45  virtual base::string16 GetMessageBody(
46      bool anchored_to_browser_action) const OVERRIDE;
47  virtual base::string16 GetOverflowText(
48      const base::string16& overflow_count) const OVERRIDE;
49  virtual base::string16 GetLearnMoreLabel() const OVERRIDE;
50  virtual GURL GetLearnMoreUrl() const OVERRIDE;
51  virtual base::string16 GetActionButtonLabel() const OVERRIDE;
52  virtual base::string16 GetDismissButtonLabel() const OVERRIDE;
53  virtual bool ShouldShowExtensionList() const OVERRIDE;
54  virtual void RestrictToSingleExtension(
55      const std::string& extension_id) OVERRIDE;
56  virtual void LogExtensionCount(size_t count) OVERRIDE;
57  virtual void LogAction(
58      ExtensionMessageBubbleController::BubbleAction
59          action) OVERRIDE;
60
61 private:
62  // Our extension service. Weak, not owned by us.
63  ExtensionService* service_;
64
65  // A weak pointer to the profile we are associated with. Not owned by us.
66  Profile* profile_;
67
68  // The ID of the extension we are showing the bubble for.
69  std::string extension_id_;
70
71  DISALLOW_COPY_AND_ASSIGN(ProxyOverriddenBubbleDelegate);
72};
73
74ProxyOverriddenBubbleDelegate::ProxyOverriddenBubbleDelegate(
75    ExtensionService* service,
76    Profile* profile)
77    : service_(service), profile_(profile) {}
78
79ProxyOverriddenBubbleDelegate::~ProxyOverriddenBubbleDelegate() {}
80
81bool ProxyOverriddenBubbleDelegate::ShouldIncludeExtension(
82    const std::string& extension_id) {
83  if (!extension_id_.empty() && extension_id_ != extension_id)
84    return false;
85
86  const Extension* extension =
87      ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID(
88          extension_id);
89  if (!extension)
90    return false;  // The extension provided is no longer enabled.
91
92  const Extension* overriding = GetExtensionOverridingProxy(profile_);
93  if (!overriding || overriding->id() != extension_id)
94    return false;
95
96  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
97  base::TimeDelta since_install =
98      base::Time::Now() - prefs->GetInstallTime(extension->id());
99  if (since_install.InDays() < kDaysSinceInstallMin)
100    return false;
101
102  if (ExtensionPrefs::Get(profile_)->HasProxyOverriddenBubbleBeenAcknowledged(
103      extension_id))
104    return false;
105
106  return true;
107}
108
109void ProxyOverriddenBubbleDelegate::AcknowledgeExtension(
110    const std::string& extension_id,
111    ExtensionMessageBubbleController::BubbleAction user_action) {
112  if (user_action != ExtensionMessageBubbleController::ACTION_EXECUTE) {
113    ExtensionPrefs::Get(profile_)->SetProxyOverriddenBubbleBeenAcknowledged(
114        extension_id, true);
115  }
116}
117
118void ProxyOverriddenBubbleDelegate::PerformAction(const ExtensionIdList& list) {
119  for (size_t i = 0; i < list.size(); ++i)
120    service_->DisableExtension(list[i], Extension::DISABLE_USER_ACTION);
121}
122
123void ProxyOverriddenBubbleDelegate::OnClose() {
124  ExtensionToolbarModel* toolbar_model =
125      ExtensionToolbarModel::Get(profile_);
126  if (toolbar_model)
127    toolbar_model->StopHighlighting();
128}
129
130base::string16 ProxyOverriddenBubbleDelegate::GetTitle() const {
131  return l10n_util::GetStringUTF16(
132      IDS_EXTENSIONS_PROXY_CONTROLLED_TITLE_HOME_PAGE_BUBBLE);
133}
134
135base::string16 ProxyOverriddenBubbleDelegate::GetMessageBody(
136    bool anchored_to_browser_action) const {
137  if (anchored_to_browser_action) {
138    return l10n_util::GetStringUTF16(
139        IDS_EXTENSIONS_PROXY_CONTROLLED_FIRST_LINE_EXTENSION_SPECIFIC);
140  } else {
141    return l10n_util::GetStringUTF16(
142        IDS_EXTENSIONS_PROXY_CONTROLLED_FIRST_LINE);
143  }
144}
145
146base::string16 ProxyOverriddenBubbleDelegate::GetOverflowText(
147    const base::string16& overflow_count) const {
148  // Does not have more than one extension in the list at a time.
149  NOTREACHED();
150  return base::string16();
151}
152
153base::string16 ProxyOverriddenBubbleDelegate::GetLearnMoreLabel() const {
154  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
155}
156
157GURL ProxyOverriddenBubbleDelegate::GetLearnMoreUrl() const {
158  return GURL(chrome::kExtensionControlledSettingLearnMoreURL);
159}
160
161base::string16 ProxyOverriddenBubbleDelegate::GetActionButtonLabel() const {
162  return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_RESTORE_SETTINGS);
163}
164
165base::string16 ProxyOverriddenBubbleDelegate::GetDismissButtonLabel() const {
166  return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_KEEP_CHANGES);
167}
168
169bool ProxyOverriddenBubbleDelegate::ShouldShowExtensionList() const {
170  return false;
171}
172
173void ProxyOverriddenBubbleDelegate::RestrictToSingleExtension(
174    const std::string& extension_id) {
175  extension_id_ = extension_id;
176}
177
178void ProxyOverriddenBubbleDelegate::LogExtensionCount(size_t count) {
179  UMA_HISTOGRAM_COUNTS_100("ProxyOverriddenBubble.ExtensionCount", count);
180}
181
182void ProxyOverriddenBubbleDelegate::LogAction(
183    ExtensionMessageBubbleController::BubbleAction action) {
184  UMA_HISTOGRAM_ENUMERATION("ProxyOverriddenBubble.UserSelection",
185                            action,
186                            ExtensionMessageBubbleController::ACTION_BOUNDARY);
187}
188
189}  // namespace
190
191////////////////////////////////////////////////////////////////////////////////
192// ProxyOverriddenBubbleController
193
194ProxyOverriddenBubbleController::ProxyOverriddenBubbleController(
195    Profile* profile)
196    : ExtensionMessageBubbleController(
197          new ProxyOverriddenBubbleDelegate(
198              ExtensionSystem::Get(profile)->extension_service(),
199              profile),
200          profile),
201      profile_(profile) {}
202
203ProxyOverriddenBubbleController::~ProxyOverriddenBubbleController() {}
204
205bool ProxyOverriddenBubbleController::ShouldShow(
206    const std::string& extension_id) {
207  if (!delegate()->ShouldIncludeExtension(extension_id))
208    return false;
209
210  delegate()->RestrictToSingleExtension(extension_id);
211  return true;
212}
213
214bool ProxyOverriddenBubbleController::CloseOnDeactivate() {
215  return false;
216}
217
218}  // namespace extensions
219