1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Use of this source code is governed by a BSD-style license that can be
3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// found in the LICENSE file.
4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/extensions/external_install_ui.h"
6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <string>
8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/bind.h"
10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/lazy_instance.h"
11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/memory/ref_counted.h"
12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/memory/scoped_ptr.h"
13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/message_loop/message_loop.h"
14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/metrics/histogram.h"
15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "base/strings/utf_string_conversions.h"
16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/app/chrome_command_ids.h"
17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/chrome_notification_types.h"
18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/extensions/extension_install_prompt.h"
19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/extensions/extension_install_ui.h"
20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/extensions/extension_service.h"
21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/extensions/extension_uninstall_dialog.h"
22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/profiles/profile.h"
23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/ui/browser.h"
24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/ui/browser_finder.h"
25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/ui/global_error/global_error.h"
26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/ui/global_error/global_error_service.h"
27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/ui/global_error/global_error_service_factory.h"
28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/browser/ui/host_desktop.h"
29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/common/extensions/extension_constants.h"
30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "chrome/common/extensions/manifest_url_handler.h"
31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "content/public/browser/notification_details.h"
32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "content/public/browser/notification_observer.h"
33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "content/public/browser/notification_registrar.h"
34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "content/public/browser/notification_source.h"
35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "extensions/common/extension.h"
36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "grit/chromium_strings.h"
37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "grit/generated_resources.h"
38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "grit/theme_resources.h"
39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/base/l10n/l10n_util.h"
40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/gfx/image/image.h"
41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/gfx/image/image_skia_operations.h"
42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "ui/gfx/size.h"
43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace extensions {
45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgnamespace {
47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Whether the external extension can use the streamlined bubble install flow.
49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool UseBubbleInstall(const Extension* extension, bool is_new_profile) {
50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  return ManifestURL::UpdatesFromGallery(extension) && !is_new_profile;
51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}
52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org}  // namespace
54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic const int kMenuCommandId = IDC_EXTERNAL_EXTENSION_ALERT;
56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass ExternalInstallGlobalError;
58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// TODO(mpcomplete): Get rid of the refcounting on this class, or document
60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// why it's necessary. Will do after refactoring to merge back with
61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// ExtensionDisabledDialogDelegate.
62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass ExternalInstallDialogDelegate
63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org    : public ExtensionInstallPrompt::Delegate,
64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org      public base::RefCountedThreadSafe<ExternalInstallDialogDelegate> {
65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org public:
66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ExternalInstallDialogDelegate(Browser* browser,
67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                ExtensionService* service,
68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                const Extension* extension,
69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                bool use_global_error);
70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Browser* browser() { return browser_; }
72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org private:
74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>;
75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  friend class ExternalInstallGlobalError;
76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual ~ExternalInstallDialogDelegate();
78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // ExtensionInstallPrompt::Delegate:
80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void InstallUIProceed() OVERRIDE;
81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // The UI for showing the install dialog when enabling.
84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  scoped_ptr<ExtensionInstallPrompt> install_ui_;
85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  Browser* browser_;
87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  base::WeakPtr<ExtensionService> service_weak_;
88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  const std::string extension_id_;
89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Only shows a menu item, no bubble. Clicking the menu item shows
92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// an external install dialog.
93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass ExternalInstallMenuAlert : public GlobalErrorWithStandardBubble,
94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                                 public content::NotificationObserver {
95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org public:
96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ExternalInstallMenuAlert(ExtensionService* service,
97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                           const Extension* extension);
98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual ~ExternalInstallMenuAlert();
99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  const Extension* extension() const { return extension_; }
101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // GlobalError implementation.
103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual Severity GetSeverity() OVERRIDE;
104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual bool HasMenuItem() OVERRIDE;
105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual int MenuItemCommandID() OVERRIDE;
106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual base::string16 MenuItemLabel() OVERRIDE;
107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual bool HasBubbleView() OVERRIDE;
109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual base::string16 GetBubbleViewTitle() OVERRIDE;
110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE;
111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // content::NotificationObserver implementation.
118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void Observe(int type,
119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       const content::NotificationSource& source,
120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                       const content::NotificationDetails& details) OVERRIDE;
121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org protected:
123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ExtensionService* service_;
124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  const Extension* extension_;
125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  content::NotificationRegistrar registrar_;
126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org};
127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Shows a menu item and a global error bubble, replacing the install dialog.
129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclass ExternalInstallGlobalError : public ExternalInstallMenuAlert {
130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org public:
131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  ExternalInstallGlobalError(ExtensionService* service,
132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                             const Extension* extension,
133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                             ExternalInstallDialogDelegate* delegate,
134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org                             const ExtensionInstallPrompt::Prompt& prompt);
135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual ~ExternalInstallGlobalError();
136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual bool HasBubbleView() OVERRIDE;
139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual gfx::Image GetBubbleViewIcon() OVERRIDE;
140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual base::string16 GetBubbleViewTitle() OVERRIDE;
141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE;
142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org
148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org protected:
149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org  // Ref-counted, but needs to be disposed of if we are dismissed without
150  // having been clicked (perhaps because the user enabled the extension
151  // manually).
152  ExternalInstallDialogDelegate* delegate_;
153  const ExtensionInstallPrompt::Prompt* prompt_;
154};
155
156static void CreateExternalInstallGlobalError(
157    base::WeakPtr<ExtensionService> service,
158    const std::string& extension_id,
159    const ExtensionInstallPrompt::ShowParams& show_params,
160    ExtensionInstallPrompt::Delegate* prompt_delegate,
161    const ExtensionInstallPrompt::Prompt& prompt) {
162  if (!service.get())
163    return;
164  const Extension* extension = service->GetInstalledExtension(extension_id);
165  if (!extension)
166    return;
167  GlobalErrorService* error_service =
168      GlobalErrorServiceFactory::GetForProfile(service->profile());
169  if (error_service->GetGlobalErrorByMenuItemCommandID(kMenuCommandId))
170    return;
171
172  ExternalInstallDialogDelegate* delegate =
173      static_cast<ExternalInstallDialogDelegate*>(prompt_delegate);
174  ExternalInstallGlobalError* error_bubble = new ExternalInstallGlobalError(
175      service.get(), extension, delegate, prompt);
176  error_service->AddGlobalError(error_bubble);
177  // Show bubble immediately if possible.
178  if (delegate->browser())
179    error_bubble->ShowBubbleView(delegate->browser());
180}
181
182static void ShowExternalInstallDialog(
183    ExtensionService* service,
184    Browser* browser,
185    const Extension* extension) {
186  // This object manages its own lifetime.
187  new ExternalInstallDialogDelegate(browser, service, extension, false);
188}
189
190// ExternalInstallDialogDelegate --------------------------------------------
191
192ExternalInstallDialogDelegate::ExternalInstallDialogDelegate(
193    Browser* browser,
194    ExtensionService* service,
195    const Extension* extension,
196    bool use_global_error)
197    : browser_(browser),
198      service_weak_(service->AsWeakPtr()),
199      extension_id_(extension->id()) {
200  AddRef();  // Balanced in Proceed or Abort.
201
202  install_ui_.reset(
203      ExtensionInstallUI::CreateInstallPromptWithBrowser(browser));
204
205  const ExtensionInstallPrompt::ShowDialogCallback callback =
206      use_global_error ?
207      base::Bind(&CreateExternalInstallGlobalError,
208                 service_weak_, extension_id_) :
209      ExtensionInstallPrompt::GetDefaultShowDialogCallback();
210  install_ui_->ConfirmExternalInstall(this, extension, callback);
211}
212
213ExternalInstallDialogDelegate::~ExternalInstallDialogDelegate() {
214}
215
216void ExternalInstallDialogDelegate::InstallUIProceed() {
217  if (!service_weak_.get())
218    return;
219  const Extension* extension =
220      service_weak_->GetInstalledExtension(extension_id_);
221  if (!extension)
222    return;
223  service_weak_->GrantPermissionsAndEnableExtension(extension);
224  Release();
225}
226
227void ExternalInstallDialogDelegate::InstallUIAbort(bool user_initiated) {
228  if (!service_weak_.get())
229    return;
230  const Extension* extension =
231      service_weak_->GetInstalledExtension(extension_id_);
232  if (!extension)
233    return;
234  service_weak_->UninstallExtension(extension_id_, false, NULL);
235  Release();
236}
237
238// ExternalInstallMenuAlert -------------------------------------------------
239
240ExternalInstallMenuAlert::ExternalInstallMenuAlert(
241    ExtensionService* service,
242    const Extension* extension)
243    : service_(service),
244      extension_(extension) {
245  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
246                 content::Source<Profile>(service->profile()));
247  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_REMOVED,
248                 content::Source<Profile>(service->profile()));
249}
250
251ExternalInstallMenuAlert::~ExternalInstallMenuAlert() {
252}
253
254GlobalError::Severity ExternalInstallMenuAlert::GetSeverity() {
255  return SEVERITY_LOW;
256}
257
258bool ExternalInstallMenuAlert::HasMenuItem() {
259  return true;
260}
261
262int ExternalInstallMenuAlert::MenuItemCommandID() {
263  return kMenuCommandId;
264}
265
266base::string16 ExternalInstallMenuAlert::MenuItemLabel() {
267  int id = -1;
268  if (extension_->is_app())
269    id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
270  else if (extension_->is_theme())
271    id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_THEME;
272  else
273    id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_EXTENSION;
274  return l10n_util::GetStringFUTF16(id, UTF8ToUTF16(extension_->name()));
275}
276
277void ExternalInstallMenuAlert::ExecuteMenuItem(Browser* browser) {
278  ShowExternalInstallDialog(service_, browser, extension_);
279}
280
281bool ExternalInstallMenuAlert::HasBubbleView() {
282  return false;
283}
284base::string16 ExternalInstallMenuAlert::GetBubbleViewTitle() {
285  return base::string16();
286}
287
288std::vector<base::string16> ExternalInstallMenuAlert::GetBubbleViewMessages() {
289  return std::vector<base::string16>();
290}
291
292base::string16 ExternalInstallMenuAlert::GetBubbleViewAcceptButtonLabel() {
293  return base::string16();
294}
295
296base::string16 ExternalInstallMenuAlert::GetBubbleViewCancelButtonLabel() {
297  return base::string16();
298}
299
300void ExternalInstallMenuAlert::OnBubbleViewDidClose(Browser* browser) {
301  NOTREACHED();
302}
303
304void ExternalInstallMenuAlert::BubbleViewAcceptButtonPressed(
305    Browser* browser) {
306  NOTREACHED();
307}
308
309void ExternalInstallMenuAlert::BubbleViewCancelButtonPressed(
310    Browser* browser) {
311  NOTREACHED();
312}
313
314void ExternalInstallMenuAlert::Observe(
315    int type,
316    const content::NotificationSource& source,
317    const content::NotificationDetails& details) {
318  // The error is invalidated if the extension has been loaded or removed.
319  DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED ||
320         type == chrome::NOTIFICATION_EXTENSION_REMOVED);
321  const Extension* extension = content::Details<const Extension>(details).ptr();
322  if (extension != extension_)
323    return;
324  GlobalErrorService* error_service =
325      GlobalErrorServiceFactory::GetForProfile(service_->profile());
326  error_service->RemoveGlobalError(this);
327  service_->AcknowledgeExternalExtension(extension_->id());
328  delete this;
329}
330
331// ExternalInstallGlobalError -----------------------------------------------
332
333ExternalInstallGlobalError::ExternalInstallGlobalError(
334    ExtensionService* service,
335    const Extension* extension,
336    ExternalInstallDialogDelegate* delegate,
337    const ExtensionInstallPrompt::Prompt& prompt)
338    : ExternalInstallMenuAlert(service, extension),
339      delegate_(delegate),
340      prompt_(&prompt) {
341}
342
343ExternalInstallGlobalError::~ExternalInstallGlobalError() {
344  if (delegate_)
345    delegate_->Release();
346}
347
348void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) {
349  ShowBubbleView(browser);
350}
351
352bool ExternalInstallGlobalError::HasBubbleView() {
353  return true;
354}
355
356gfx::Image ExternalInstallGlobalError::GetBubbleViewIcon() {
357  if (prompt_->icon().IsEmpty())
358    return GlobalErrorWithStandardBubble::GetBubbleViewIcon();
359  // Scale icon to a reasonable size.
360  return gfx::Image(gfx::ImageSkiaOperations::CreateResizedImage(
361      *prompt_->icon().ToImageSkia(),
362      skia::ImageOperations::RESIZE_BEST,
363      gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
364                extension_misc::EXTENSION_ICON_SMALL)));
365}
366
367base::string16 ExternalInstallGlobalError::GetBubbleViewTitle() {
368  return prompt_->GetDialogTitle();
369}
370
371std::vector<base::string16>
372ExternalInstallGlobalError::GetBubbleViewMessages() {
373  std::vector<base::string16> messages;
374  messages.push_back(prompt_->GetHeading());
375  if (prompt_->GetPermissionCount()) {
376    messages.push_back(prompt_->GetPermissionsHeading());
377    for (size_t i = 0; i < prompt_->GetPermissionCount(); ++i) {
378      messages.push_back(l10n_util::GetStringFUTF16(
379          IDS_EXTENSION_PERMISSION_LINE,
380          prompt_->GetPermission(i)));
381    }
382  }
383  // TODO(yoz): OAuth issue advice?
384  return messages;
385}
386
387base::string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() {
388  return prompt_->GetAcceptButtonLabel();
389}
390
391base::string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() {
392  return prompt_->GetAbortButtonLabel();
393}
394
395void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) {
396}
397
398void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed(
399    Browser* browser) {
400  ExternalInstallDialogDelegate* delegate = delegate_;
401  delegate_ = NULL;
402  delegate->InstallUIProceed();
403}
404
405void ExternalInstallGlobalError::BubbleViewCancelButtonPressed(
406    Browser* browser) {
407  ExternalInstallDialogDelegate* delegate = delegate_;
408  delegate_ = NULL;
409  delegate->InstallUIAbort(true);
410}
411
412// Public interface ---------------------------------------------------------
413
414void AddExternalInstallError(ExtensionService* service,
415                             const Extension* extension,
416                             bool is_new_profile) {
417  GlobalErrorService* error_service =
418      GlobalErrorServiceFactory::GetForProfile(service->profile());
419  if (error_service->GetGlobalErrorByMenuItemCommandID(kMenuCommandId))
420    return;
421
422  if (UseBubbleInstall(extension, is_new_profile)) {
423    Browser* browser = NULL;
424#if !defined(OS_ANDROID)
425    browser = chrome::FindTabbedBrowser(service->profile(),
426                                        true,
427                                        chrome::GetActiveDesktop());
428#endif
429    new ExternalInstallDialogDelegate(browser, service, extension, true);
430  } else {
431    error_service->AddGlobalError(
432        new ExternalInstallMenuAlert(service, extension));
433  }
434}
435
436void RemoveExternalInstallError(ExtensionService* service) {
437  GlobalErrorService* error_service =
438      GlobalErrorServiceFactory::GetForProfile(service->profile());
439  GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
440      kMenuCommandId);
441  if (error) {
442    error_service->RemoveGlobalError(error);
443    delete error;
444  }
445}
446
447bool HasExternalInstallError(ExtensionService* service) {
448  GlobalErrorService* error_service =
449      GlobalErrorServiceFactory::GetForProfile(service->profile());
450  GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
451      kMenuCommandId);
452  return !!error;
453}
454
455bool HasExternalInstallBubble(ExtensionService* service) {
456  GlobalErrorService* error_service =
457      GlobalErrorServiceFactory::GetForProfile(service->profile());
458  GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
459      kMenuCommandId);
460  return error && error->HasBubbleView();
461}
462
463}  // namespace extensions
464