blob: 19bc8f430733c4e2a22586f4d3c98a186714eee2 [file] [log] [blame]
[email protected]612a1cb12012-10-17 13:18:031// 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/external_install_ui.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/lazy_instance.h"
11#include "base/memory/ref_counted.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/message_loop.h"
14#include "base/metrics/histogram.h"
15#include "base/utf_string_conversions.h"
16#include "chrome/app/chrome_command_ids.h"
17#include "chrome/browser/extensions/extension_install_prompt.h"
[email protected]91e51d612012-10-21 23:03:0518#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]612a1cb12012-10-17 13:18:0319#include "chrome/browser/extensions/extension_service.h"
20#include "chrome/browser/extensions/extension_uninstall_dialog.h"
21#include "chrome/browser/profiles/profile.h"
22#include "chrome/browser/ui/browser.h"
23#include "chrome/browser/ui/global_error/global_error.h"
24#include "chrome/browser/ui/global_error/global_error_service.h"
25#include "chrome/browser/ui/global_error/global_error_service_factory.h"
26#include "chrome/common/chrome_notification_types.h"
27#include "chrome/common/extensions/extension.h"
28#include "content/public/browser/notification_details.h"
29#include "content/public/browser/notification_observer.h"
30#include "content/public/browser/notification_registrar.h"
31#include "content/public/browser/notification_source.h"
32#include "grit/chromium_strings.h"
33#include "grit/generated_resources.h"
34#include "grit/theme_resources.h"
35#include "ui/base/l10n/l10n_util.h"
36
37namespace extensions {
38
39static const int kMenuCommandId = IDC_EXTERNAL_EXTENSION_ALERT;
40
41// ExternalInstallDialogDelegate --------------------------------------------
42
43// TODO(mpcomplete): Get rid of the refcounting on this class, or document
44// why it's necessary. Will do after refactoring to merge back with
45// ExtensionDisabledDialogDelegate.
46class ExternalInstallDialogDelegate
47 : public ExtensionInstallPrompt::Delegate,
48 public base::RefCountedThreadSafe<ExternalInstallDialogDelegate> {
49 public:
50 ExternalInstallDialogDelegate(Browser* browser,
51 ExtensionService* service,
52 const Extension* extension);
53
54 private:
55 friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>;
56
57 virtual ~ExternalInstallDialogDelegate();
58
59 // ExtensionInstallPrompt::Delegate:
60 virtual void InstallUIProceed() OVERRIDE;
61 virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
62
63 // The UI for showing the install dialog when enabling.
64 scoped_ptr<ExtensionInstallPrompt> install_ui_;
65
66 ExtensionService* service_;
67 const Extension* extension_;
68};
69
70ExternalInstallDialogDelegate::ExternalInstallDialogDelegate(
71 Browser* browser,
72 ExtensionService* service,
73 const Extension* extension)
74 : service_(service), extension_(extension) {
75 AddRef(); // Balanced in Proceed or Abort.
76
[email protected]91e51d612012-10-21 23:03:0577 install_ui_.reset(
78 ExtensionInstallUI::CreateInstallPromptWithBrowser(browser));
[email protected]612a1cb12012-10-17 13:18:0379 install_ui_->ConfirmExternalInstall(this, extension_);
80}
81
82ExternalInstallDialogDelegate::~ExternalInstallDialogDelegate() {
83}
84
85void ExternalInstallDialogDelegate::InstallUIProceed() {
86 service_->GrantPermissionsAndEnableExtension(
87 extension_, install_ui_->record_oauth2_grant());
88 Release();
89}
90
91void ExternalInstallDialogDelegate::InstallUIAbort(bool user_initiated) {
92 service_->UninstallExtension(extension_->id(), false, NULL);
93 Release();
94}
95
96static void ShowExternalInstallDialog(ExtensionService* service,
97 Browser* browser,
98 const Extension* extension) {
99 // This object manages its own lifetime.
100 new ExternalInstallDialogDelegate(browser, service, extension);
101}
102
103// ExternalInstallGlobalError -----------------------------------------------
104
105class ExternalInstallGlobalError : public GlobalError,
106 public content::NotificationObserver {
107 public:
108 ExternalInstallGlobalError(ExtensionService* service,
109 const Extension* extension);
110 virtual ~ExternalInstallGlobalError();
111
112 const Extension* extension() const { return extension_; }
113
114 // GlobalError implementation.
115 virtual bool HasBadge() OVERRIDE;
116 virtual int GetBadgeResourceID() OVERRIDE;
117 virtual bool HasMenuItem() OVERRIDE;
118 virtual int MenuItemCommandID() OVERRIDE;
119 virtual string16 MenuItemLabel() OVERRIDE;
120 virtual int MenuItemIconResourceID() OVERRIDE;
121 virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
122 virtual bool HasBubbleView() OVERRIDE;
123 virtual string16 GetBubbleViewTitle() OVERRIDE;
124 virtual string16 GetBubbleViewMessage() OVERRIDE;
125 virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
126 virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
127 virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
128 virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
129 virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
130
131 // content::NotificationObserver implementation.
132 virtual void Observe(int type,
133 const content::NotificationSource& source,
134 const content::NotificationDetails& details) OVERRIDE;
135
136 private:
137 ExtensionService* service_;
138 const Extension* extension_;
[email protected]612a1cb12012-10-17 13:18:03139 content::NotificationRegistrar registrar_;
140};
141
142ExternalInstallGlobalError::ExternalInstallGlobalError(
143 ExtensionService* service,
144 const Extension* extension)
145 : service_(service),
[email protected]d96eb512012-11-01 23:44:08146 extension_(extension) {
[email protected]612a1cb12012-10-17 13:18:03147 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
148 content::Source<Profile>(service->profile()));
149 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
150 content::Source<Profile>(service->profile()));
151}
152
153ExternalInstallGlobalError::~ExternalInstallGlobalError() {
[email protected]612a1cb12012-10-17 13:18:03154}
155
156bool ExternalInstallGlobalError::HasBadge() {
157 return true;
158}
159
160int ExternalInstallGlobalError::GetBadgeResourceID() {
161 return IDR_UPDATE_BADGE_EXTENSION;
162}
163
164bool ExternalInstallGlobalError::HasMenuItem() {
165 return true;
166}
167
168int ExternalInstallGlobalError::MenuItemCommandID() {
169 return kMenuCommandId;
170}
171
172int ExternalInstallGlobalError::MenuItemIconResourceID() {
173 return IDR_UPDATE_MENU_EXTENSION;
174}
175
176string16 ExternalInstallGlobalError::MenuItemLabel() {
[email protected]846606012012-10-19 18:42:25177 int id = -1;
178 if (extension_->is_app())
179 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
180 else if (extension_->is_theme())
181 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_THEME;
182 else
183 id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_EXTENSION;
184 return l10n_util::GetStringFUTF16(id, UTF8ToUTF16(extension_->name()));
[email protected]612a1cb12012-10-17 13:18:03185}
186
187void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) {
188 ShowExternalInstallDialog(service_, browser, extension_);
189}
190
191bool ExternalInstallGlobalError::HasBubbleView() {
192 return false;
193}
194
195string16 ExternalInstallGlobalError::GetBubbleViewTitle() {
196 return string16();
197}
198
199string16 ExternalInstallGlobalError::GetBubbleViewMessage() {
200 return string16();
201}
202
203string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() {
204 return string16();
205}
206
207string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() {
208 return string16();
209}
210
211void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) {
212 NOTREACHED();
213}
214
215void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed(
216 Browser* browser) {
217 NOTREACHED();
218}
219
220void ExternalInstallGlobalError::BubbleViewCancelButtonPressed(
221 Browser* browser) {
222 NOTREACHED();
223}
224
225void ExternalInstallGlobalError::Observe(
226 int type,
227 const content::NotificationSource& source,
228 const content::NotificationDetails& details) {
229 const Extension* extension = NULL;
[email protected]d96eb512012-11-01 23:44:08230 // The error is invalidated if the extension has been reloaded or unloaded.
[email protected]612a1cb12012-10-17 13:18:03231 if (type == chrome::NOTIFICATION_EXTENSION_LOADED) {
232 extension = content::Details<const Extension>(details).ptr();
233 } else {
234 DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNLOADED, type);
235 extensions::UnloadedExtensionInfo* info =
236 content::Details<extensions::UnloadedExtensionInfo>(details).ptr();
237 extension = info->extension;
238 }
239 if (extension == extension_) {
240 GlobalErrorService* error_service =
241 GlobalErrorServiceFactory::GetForProfile(service_->profile());
242 error_service->RemoveGlobalError(this);
[email protected]612a1cb12012-10-17 13:18:03243 service_->AcknowledgeExternalExtension(extension_->id());
244 delete this;
245 }
246}
247
248// Public interface ---------------------------------------------------------
249
250bool AddExternalInstallError(ExtensionService* service,
251 const Extension* extension) {
252 GlobalErrorService* error_service =
253 GlobalErrorServiceFactory::GetForProfile(service->profile());
254 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
255 kMenuCommandId);
256 if (error)
257 return false;
258
259 error_service->AddGlobalError(
260 new ExternalInstallGlobalError(service, extension));
261 return true;
262}
263
264void RemoveExternalInstallError(ExtensionService* service) {
265 GlobalErrorService* error_service =
266 GlobalErrorServiceFactory::GetForProfile(service->profile());
267 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
268 kMenuCommandId);
269 if (error) {
270 error_service->RemoveGlobalError(error);
271 delete error;
272 }
273}
274
275bool HasExternalInstallError(ExtensionService* service) {
276 GlobalErrorService* error_service =
277 GlobalErrorServiceFactory::GetForProfile(service->profile());
278 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
279 kMenuCommandId);
280 return !!error;
281}
282
283} // namespace extensions