Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_disabled_ui.cc
blobece2144a677674b42c38b75b017a167c1bc1add8
1 // 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.
5 #include "chrome/browser/extensions/extension_disabled_ui.h"
7 #include <string>
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/message_loop.h"
14 #include "base/metrics/histogram.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/app/chrome_command_ids.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/extensions/extension_install_prompt.h"
19 #include "chrome/browser/extensions/extension_install_ui.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
22 #include "chrome/browser/extensions/extension_util.h"
23 #include "chrome/browser/extensions/image_loader.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/ui/browser.h"
26 #include "chrome/browser/ui/global_error/global_error.h"
27 #include "chrome/browser/ui/global_error/global_error_service.h"
28 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
29 #include "chrome/browser/ui/tabs/tab_strip_model.h"
30 #include "content/public/browser/notification_details.h"
31 #include "content/public/browser/notification_observer.h"
32 #include "content/public/browser/notification_registrar.h"
33 #include "content/public/browser/notification_source.h"
34 #include "extensions/common/extension.h"
35 #include "extensions/common/extension_icon_set.h"
36 #include "extensions/common/manifest_handlers/icons_handler.h"
37 #include "extensions/common/permissions/permission_message_provider.h"
38 #include "extensions/common/permissions/permission_set.h"
39 #include "grit/chromium_strings.h"
40 #include "grit/generated_resources.h"
41 #include "grit/theme_resources.h"
42 #include "ui/base/l10n/l10n_util.h"
43 #include "ui/gfx/image/image.h"
44 #include "ui/gfx/image/image_skia_operations.h"
45 #include "ui/gfx/size.h"
47 using extensions::Extension;
49 namespace {
51 static const int kIconSize = extension_misc::EXTENSION_ICON_SMALL;
53 static base::LazyInstance<
54 std::bitset<IDC_EXTENSION_DISABLED_LAST -
55 IDC_EXTENSION_DISABLED_FIRST + 1> >
56 menu_command_ids = LAZY_INSTANCE_INITIALIZER;
58 // Get an available menu ID.
59 int GetMenuCommandID() {
60 int id;
61 for (id = IDC_EXTENSION_DISABLED_FIRST;
62 id <= IDC_EXTENSION_DISABLED_LAST; ++id) {
63 if (!menu_command_ids.Get()[id - IDC_EXTENSION_DISABLED_FIRST]) {
64 menu_command_ids.Get().set(id - IDC_EXTENSION_DISABLED_FIRST);
65 return id;
68 // This should not happen.
69 DCHECK(id <= IDC_EXTENSION_DISABLED_LAST) <<
70 "No available menu command IDs for ExtensionDisabledGlobalError";
71 return IDC_EXTENSION_DISABLED_LAST;
74 // Make a menu ID available when it is no longer used.
75 void ReleaseMenuCommandID(int id) {
76 menu_command_ids.Get().reset(id - IDC_EXTENSION_DISABLED_FIRST);
79 } // namespace
81 // ExtensionDisabledDialogDelegate --------------------------------------------
83 class ExtensionDisabledDialogDelegate
84 : public ExtensionInstallPrompt::Delegate,
85 public base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate> {
86 public:
87 ExtensionDisabledDialogDelegate(ExtensionService* service,
88 scoped_ptr<ExtensionInstallPrompt> install_ui,
89 const Extension* extension);
91 private:
92 friend class base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate>;
94 virtual ~ExtensionDisabledDialogDelegate();
96 // ExtensionInstallPrompt::Delegate:
97 virtual void InstallUIProceed() OVERRIDE;
98 virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
100 // The UI for showing the install dialog when enabling.
101 scoped_ptr<ExtensionInstallPrompt> install_ui_;
103 ExtensionService* service_;
104 const Extension* extension_;
107 ExtensionDisabledDialogDelegate::ExtensionDisabledDialogDelegate(
108 ExtensionService* service,
109 scoped_ptr<ExtensionInstallPrompt> install_ui,
110 const Extension* extension)
111 : install_ui_(install_ui.Pass()),
112 service_(service),
113 extension_(extension) {
114 AddRef(); // Balanced in Proceed or Abort.
115 install_ui_->ConfirmReEnable(this, extension_);
118 ExtensionDisabledDialogDelegate::~ExtensionDisabledDialogDelegate() {
121 void ExtensionDisabledDialogDelegate::InstallUIProceed() {
122 service_->GrantPermissionsAndEnableExtension(extension_);
123 Release();
126 void ExtensionDisabledDialogDelegate::InstallUIAbort(bool user_initiated) {
127 std::string histogram_name = user_initiated ?
128 "Extensions.Permissions_ReEnableCancel" :
129 "Extensions.Permissions_ReEnableAbort";
130 ExtensionService::RecordPermissionMessagesHistogram(
131 extension_, histogram_name.c_str());
133 // Do nothing. The extension will remain disabled.
134 Release();
137 // ExtensionDisabledGlobalError -----------------------------------------------
139 class ExtensionDisabledGlobalError : public GlobalErrorWithStandardBubble,
140 public content::NotificationObserver,
141 public ExtensionUninstallDialog::Delegate {
142 public:
143 ExtensionDisabledGlobalError(ExtensionService* service,
144 const Extension* extension,
145 const gfx::Image& icon);
146 virtual ~ExtensionDisabledGlobalError();
148 // GlobalError implementation.
149 virtual Severity GetSeverity() OVERRIDE;
150 virtual bool HasMenuItem() OVERRIDE;
151 virtual int MenuItemCommandID() OVERRIDE;
152 virtual base::string16 MenuItemLabel() OVERRIDE;
153 virtual void ExecuteMenuItem(Browser* browser) OVERRIDE;
154 virtual gfx::Image GetBubbleViewIcon() OVERRIDE;
155 virtual base::string16 GetBubbleViewTitle() OVERRIDE;
156 virtual std::vector<base::string16> GetBubbleViewMessages() OVERRIDE;
157 virtual base::string16 GetBubbleViewAcceptButtonLabel() OVERRIDE;
158 virtual base::string16 GetBubbleViewCancelButtonLabel() OVERRIDE;
159 virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE;
160 virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE;
161 virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE;
163 // ExtensionUninstallDialog::Delegate implementation.
164 virtual void ExtensionUninstallAccepted() OVERRIDE;
165 virtual void ExtensionUninstallCanceled() OVERRIDE;
167 // content::NotificationObserver implementation.
168 virtual void Observe(int type,
169 const content::NotificationSource& source,
170 const content::NotificationDetails& details) OVERRIDE;
172 private:
173 ExtensionService* service_;
174 const Extension* extension_;
175 gfx::Image icon_;
177 // How the user responded to the error; used for metrics.
178 enum UserResponse {
179 IGNORED,
180 REENABLE,
181 UNINSTALL,
182 EXTENSION_DISABLED_UI_BUCKET_BOUNDARY
184 UserResponse user_response_;
186 scoped_ptr<ExtensionUninstallDialog> uninstall_dialog_;
188 // Menu command ID assigned for this extension's error.
189 int menu_command_id_;
191 content::NotificationRegistrar registrar_;
194 // TODO(yoz): create error at startup for disabled extensions.
195 ExtensionDisabledGlobalError::ExtensionDisabledGlobalError(
196 ExtensionService* service,
197 const Extension* extension,
198 const gfx::Image& icon)
199 : service_(service),
200 extension_(extension),
201 icon_(icon),
202 user_response_(IGNORED),
203 menu_command_id_(GetMenuCommandID()) {
204 if (icon_.IsEmpty()) {
205 icon_ = gfx::Image(
206 gfx::ImageSkiaOperations::CreateResizedImage(
207 extension_->is_app() ?
208 extensions::util::GetDefaultAppIcon() :
209 extensions::util::GetDefaultExtensionIcon(),
210 skia::ImageOperations::RESIZE_BEST,
211 gfx::Size(kIconSize, kIconSize)));
213 registrar_.Add(this,
214 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
215 content::Source<Profile>(service->profile()));
216 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_REMOVED,
217 content::Source<Profile>(service->profile()));
220 ExtensionDisabledGlobalError::~ExtensionDisabledGlobalError() {
221 ReleaseMenuCommandID(menu_command_id_);
222 UMA_HISTOGRAM_ENUMERATION("Extensions.DisabledUIUserResponse",
223 user_response_,
224 EXTENSION_DISABLED_UI_BUCKET_BOUNDARY);
227 GlobalError::Severity ExtensionDisabledGlobalError::GetSeverity() {
228 return SEVERITY_LOW;
231 bool ExtensionDisabledGlobalError::HasMenuItem() {
232 return true;
235 int ExtensionDisabledGlobalError::MenuItemCommandID() {
236 return menu_command_id_;
239 base::string16 ExtensionDisabledGlobalError::MenuItemLabel() {
240 return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_ERROR_TITLE,
241 base::UTF8ToUTF16(extension_->name()));
244 void ExtensionDisabledGlobalError::ExecuteMenuItem(Browser* browser) {
245 ShowBubbleView(browser);
248 gfx::Image ExtensionDisabledGlobalError::GetBubbleViewIcon() {
249 return icon_;
252 base::string16 ExtensionDisabledGlobalError::GetBubbleViewTitle() {
253 return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_ERROR_TITLE,
254 base::UTF8ToUTF16(extension_->name()));
257 std::vector<base::string16>
258 ExtensionDisabledGlobalError::GetBubbleViewMessages() {
259 std::vector<base::string16> messages;
260 messages.push_back(l10n_util::GetStringFUTF16(
261 extension_->is_app() ?
262 IDS_APP_DISABLED_ERROR_LABEL : IDS_EXTENSION_DISABLED_ERROR_LABEL,
263 base::UTF8ToUTF16(extension_->name())));
264 messages.push_back(l10n_util::GetStringUTF16(
265 IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO));
266 std::vector<base::string16> permission_warnings =
267 extensions::PermissionMessageProvider::Get()->GetWarningMessages(
268 extension_->GetActivePermissions(), extension_->GetType());
269 for (size_t i = 0; i < permission_warnings.size(); ++i) {
270 messages.push_back(l10n_util::GetStringFUTF16(
271 IDS_EXTENSION_PERMISSION_LINE, permission_warnings[i]));
273 return messages;
276 base::string16 ExtensionDisabledGlobalError::GetBubbleViewAcceptButtonLabel() {
277 return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON);
280 base::string16 ExtensionDisabledGlobalError::GetBubbleViewCancelButtonLabel() {
281 return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL);
284 void ExtensionDisabledGlobalError::OnBubbleViewDidClose(Browser* browser) {
287 void ExtensionDisabledGlobalError::BubbleViewAcceptButtonPressed(
288 Browser* browser) {
289 // Delay extension reenabling so this bubble closes properly.
290 base::MessageLoop::current()->PostTask(FROM_HERE,
291 base::Bind(&ExtensionService::GrantPermissionsAndEnableExtension,
292 service_->AsWeakPtr(), extension_));
295 void ExtensionDisabledGlobalError::BubbleViewCancelButtonPressed(
296 Browser* browser) {
297 #if !defined(OS_ANDROID)
298 uninstall_dialog_.reset(
299 ExtensionUninstallDialog::Create(service_->profile(), browser, this));
300 // Delay showing the uninstall dialog, so that this function returns
301 // immediately, to close the bubble properly. See crbug.com/121544.
302 base::MessageLoop::current()->PostTask(FROM_HERE,
303 base::Bind(&ExtensionUninstallDialog::ConfirmUninstall,
304 uninstall_dialog_->AsWeakPtr(), extension_));
305 #endif // !defined(OS_ANDROID)
308 void ExtensionDisabledGlobalError::ExtensionUninstallAccepted() {
309 service_->UninstallExtension(extension_->id(), false, NULL);
312 void ExtensionDisabledGlobalError::ExtensionUninstallCanceled() {
313 // Nothing happens, and the error is still there.
316 void ExtensionDisabledGlobalError::Observe(
317 int type,
318 const content::NotificationSource& source,
319 const content::NotificationDetails& details) {
320 // The error is invalidated if the extension has been loaded or removed.
321 DCHECK(type == chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED ||
322 type == chrome::NOTIFICATION_EXTENSION_REMOVED);
323 const Extension* extension = content::Details<const Extension>(details).ptr();
324 if (extension != extension_)
325 return;
326 GlobalErrorServiceFactory::GetForProfile(service_->profile())->
327 RemoveGlobalError(this);
329 if (type == chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED)
330 user_response_ = REENABLE;
331 else if (type == chrome::NOTIFICATION_EXTENSION_REMOVED)
332 user_response_ = UNINSTALL;
333 delete this;
336 // Globals --------------------------------------------------------------------
338 namespace extensions {
340 void AddExtensionDisabledErrorWithIcon(base::WeakPtr<ExtensionService> service,
341 const std::string& extension_id,
342 const gfx::Image& icon) {
343 if (!service.get())
344 return;
345 const Extension* extension = service->GetInstalledExtension(extension_id);
346 if (extension) {
347 GlobalErrorServiceFactory::GetForProfile(service->profile())
348 ->AddGlobalError(
349 new ExtensionDisabledGlobalError(service.get(), extension, icon));
353 void AddExtensionDisabledError(ExtensionService* service,
354 const Extension* extension) {
355 // Do not display notifications for ephemeral apps that have been disabled.
356 // Instead, a prompt will be shown the next time the app is launched.
357 if (extension->is_ephemeral())
358 return;
360 extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
361 extension, kIconSize, ExtensionIconSet::MATCH_BIGGER);
362 gfx::Size size(kIconSize, kIconSize);
363 ImageLoader::Get(service->profile())->LoadImageAsync(
364 extension, image, size,
365 base::Bind(&AddExtensionDisabledErrorWithIcon,
366 service->AsWeakPtr(), extension->id()));
369 void ShowExtensionDisabledDialog(ExtensionService* service,
370 content::WebContents* web_contents,
371 const Extension* extension) {
372 scoped_ptr<ExtensionInstallPrompt> install_ui(
373 new ExtensionInstallPrompt(web_contents));
374 // This object manages its own lifetime.
375 new ExtensionDisabledDialogDelegate(service, install_ui.Pass(), extension);
378 } // namespace extensions