summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/external_install_ui.cc
blob: cb7cb10263d639ae1fc53d46f5f4f0ae97b3ac1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/external_install_ui.h"

#include <string>

#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/global_error/global_error.h"
#include "chrome/browser/ui/global_error/global_error_service.h"
#include "chrome/browser/ui/global_error/global_error_service_factory.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_source.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace extensions {

static const int kMenuCommandId = IDC_EXTERNAL_EXTENSION_ALERT;

// ExternalInstallDialogDelegate --------------------------------------------

// TODO(mpcomplete): Get rid of the refcounting on this class, or document
// why it's necessary. Will do after refactoring to merge back with
// ExtensionDisabledDialogDelegate.
class ExternalInstallDialogDelegate
    : public ExtensionInstallPrompt::Delegate,
      public base::RefCountedThreadSafe<ExternalInstallDialogDelegate> {
 public:
  ExternalInstallDialogDelegate(Browser* browser,
                                ExtensionService* service,
                                const Extension* extension);

 private:
  friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>;

  virtual ~ExternalInstallDialogDelegate();

  // ExtensionInstallPrompt::Delegate:
  virtual void InstallUIProceed() OVERRIDE;
  virtual void InstallUIAbort(bool user_initiated) OVERRIDE;

  // The UI for showing the install dialog when enabling.
  scoped_ptr<ExtensionInstallPrompt> install_ui_;

  ExtensionService* service_;
  const Extension* extension_;
};

ExternalInstallDialogDelegate::ExternalInstallDialogDelegate(
    Browser* browser,
    ExtensionService* service,
    const Extension* extension)
    : service_(service), extension_(extension) {
  AddRef();  // Balanced in Proceed or Abort.

  install_ui_.reset(
      ExtensionInstallUI::CreateInstallPromptWithBrowser(browser));
  install_ui_->ConfirmExternalInstall(this, extension_);
}

ExternalInstallDialogDelegate::~ExternalInstallDialogDelegate() {
}

void ExternalInstallDialogDelegate::InstallUIProceed() {
  service_->GrantPermissionsAndEnableExtension(extension_);
  Release();
}

void ExternalInstallDialogDelegate::InstallUIAbort(bool user_initiated) {
  service_->UninstallExtension(extension_->id(), false, NULL);
  Release();
}

static void ShowExternalInstallDialog(ExtensionService* service,
                                      Browser* browser,
                                      const Extension* extension) {
  // This object manages its own lifetime.
  new ExternalInstallDialogDelegate(browser, service, extension);
}

// ExternalInstallGlobalError -----------------------------------------------

class ExternalInstallGlobalError : public GlobalError,
                                   public content::NotificationObserver {
 public:
  ExternalInstallGlobalError(ExtensionService* service,
                               const Extension* extension);
  virtual ~ExternalInstallGlobalError();

  const Extension* extension() const { return extension_; }

  // GlobalError implementation.
  virtual Severity GetSeverity() OVERRIDE;
  virtual bool HasMenuItem() OVERRIDE;
  virtual int MenuItemCommandID() OVERRIDE;
  virtual string16 MenuItemLabel() OVERRIDE;
  virtual int MenuItemIconResourceID() OVERRIDE;
  virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
  virtual bool HasBubbleView() OVERRIDE;
  virtual string16 GetBubbleViewTitle() OVERRIDE;
  virtual std::vector<string16> GetBubbleViewMessages() OVERRIDE;
  virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
  virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
  virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
  virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
  virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;

  // content::NotificationObserver implementation.
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

 private:
  ExtensionService* service_;
  const Extension* extension_;
  content::NotificationRegistrar registrar_;
};

ExternalInstallGlobalError::ExternalInstallGlobalError(
    ExtensionService* service,
    const Extension* extension)
    : service_(service),
      extension_(extension) {
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
                 content::Source<Profile>(service->profile()));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
                 content::Source<Profile>(service->profile()));
}

ExternalInstallGlobalError::~ExternalInstallGlobalError() {
}

GlobalError::Severity ExternalInstallGlobalError::GetSeverity() {
  return SEVERITY_LOW;
}

bool ExternalInstallGlobalError::HasMenuItem() {
  return true;
}

int ExternalInstallGlobalError::MenuItemCommandID() {
  return kMenuCommandId;
}

int ExternalInstallGlobalError::MenuItemIconResourceID() {
  return IDR_UPDATE_MENU_EXTENSION;
}

string16 ExternalInstallGlobalError::MenuItemLabel() {
  int id = -1;
  if (extension_->is_app())
    id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_APP;
  else if (extension_->is_theme())
    id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_THEME;
  else
    id = IDS_EXTENSION_EXTERNAL_INSTALL_ALERT_EXTENSION;
  return l10n_util::GetStringFUTF16(id, UTF8ToUTF16(extension_->name()));
}

void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) {
  ShowExternalInstallDialog(service_, browser, extension_);
}

bool ExternalInstallGlobalError::HasBubbleView() {
  return false;
}

string16 ExternalInstallGlobalError::GetBubbleViewTitle() {
  return string16();
}

std::vector<string16> ExternalInstallGlobalError::GetBubbleViewMessages() {
  return std::vector<string16>();
}

string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() {
  return string16();
}

string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() {
  return string16();
}

void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) {
  NOTREACHED();
}

void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed(
    Browser* browser) {
  NOTREACHED();
}

void ExternalInstallGlobalError::BubbleViewCancelButtonPressed(
    Browser* browser) {
  NOTREACHED();
}

void ExternalInstallGlobalError::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  const Extension* extension = NULL;
  // The error is invalidated if the extension has been reloaded or unloaded.
  if (type == chrome::NOTIFICATION_EXTENSION_LOADED) {
    extension = content::Details<const Extension>(details).ptr();
  } else {
    DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNLOADED, type);
    extensions::UnloadedExtensionInfo* info =
        content::Details<extensions::UnloadedExtensionInfo>(details).ptr();
    extension = info->extension;
  }
  if (extension == extension_) {
    GlobalErrorService* error_service =
        GlobalErrorServiceFactory::GetForProfile(service_->profile());
    error_service->RemoveGlobalError(this);
    service_->AcknowledgeExternalExtension(extension_->id());
    delete this;
  }
}

// Public interface ---------------------------------------------------------

bool AddExternalInstallError(ExtensionService* service,
                             const Extension* extension) {
  GlobalErrorService* error_service =
      GlobalErrorServiceFactory::GetForProfile(service->profile());
  GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
      kMenuCommandId);
  if (error)
    return false;

  error_service->AddGlobalError(
      new ExternalInstallGlobalError(service, extension));
  return true;
}

void RemoveExternalInstallError(ExtensionService* service) {
  GlobalErrorService* error_service =
      GlobalErrorServiceFactory::GetForProfile(service->profile());
  GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
      kMenuCommandId);
  if (error) {
    error_service->RemoveGlobalError(error);
    delete error;
  }
}

bool HasExternalInstallError(ExtensionService* service) {
  GlobalErrorService* error_service =
      GlobalErrorServiceFactory::GetForProfile(service->profile());
  GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID(
      kMenuCommandId);
  return !!error;
}

}  // namespace extensions