| OLD | NEW |
| (Empty) | |
| 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. |
| 4 |
| 5 #include "chrome/browser/extensions/extension_disabled_ui.h" |
| 6 |
| 7 #include <string> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/lazy_instance.h" |
| 11 #include "base/message_loop.h" |
| 12 #include "base/memory/ref_counted.h" |
| 13 #include "base/memory/scoped_ptr.h" |
| 14 #include "base/utf_string_conversions.h" |
| 15 #include "chrome/app/chrome_command_ids.h" |
| 16 #include "chrome/browser/extensions/extension_install_ui.h" |
| 17 #include "chrome/browser/extensions/extension_service.h" |
| 18 #include "chrome/browser/extensions/extension_uninstall_dialog.h" |
| 19 #include "chrome/browser/profiles/profile.h" |
| 20 #include "chrome/browser/ui/browser.h" |
| 21 #include "chrome/browser/ui/global_error.h" |
| 22 #include "chrome/browser/ui/global_error_service.h" |
| 23 #include "chrome/browser/ui/global_error_service_factory.h" |
| 24 #include "chrome/common/chrome_notification_types.h" |
| 25 #include "chrome/common/extensions/extension.h" |
| 26 #include "content/public/browser/notification_details.h" |
| 27 #include "content/public/browser/notification_observer.h" |
| 28 #include "content/public/browser/notification_registrar.h" |
| 29 #include "content/public/browser/notification_source.h" |
| 30 #include "grit/chromium_strings.h" |
| 31 #include "grit/generated_resources.h" |
| 32 #include "ui/base/l10n/l10n_util.h" |
| 33 |
| 34 namespace { |
| 35 |
| 36 static base::LazyInstance< |
| 37 std::bitset<IDC_EXTENSION_DISABLED_LAST - |
| 38 IDC_EXTENSION_DISABLED_FIRST + 1> > |
| 39 menu_command_ids = LAZY_INSTANCE_INITIALIZER; |
| 40 |
| 41 // Get an available menu ID. |
| 42 int GetMenuCommandID() { |
| 43 int id; |
| 44 for (id = IDC_EXTENSION_DISABLED_FIRST; |
| 45 id <= IDC_EXTENSION_DISABLED_LAST; ++id) { |
| 46 if (!menu_command_ids.Get()[id - IDC_EXTENSION_DISABLED_FIRST]) { |
| 47 menu_command_ids.Get().set(id - IDC_EXTENSION_DISABLED_FIRST); |
| 48 return id; |
| 49 } |
| 50 } |
| 51 // This should not happen. |
| 52 DCHECK(id <= IDC_EXTENSION_DISABLED_LAST) << |
| 53 "No available menu command IDs for ExtensionDisabledGlobalError"; |
| 54 return IDC_EXTENSION_DISABLED_LAST; |
| 55 } |
| 56 |
| 57 // Make a menu ID available when it is no longer used. |
| 58 void ReleaseMenuCommandID(int id) { |
| 59 menu_command_ids.Get().reset(id - IDC_EXTENSION_DISABLED_FIRST); |
| 60 } |
| 61 |
| 62 } // namespace |
| 63 |
| 64 // ExtensionDisabledDialogDelegate -------------------------------------------- |
| 65 |
| 66 class ExtensionDisabledDialogDelegate |
| 67 : public ExtensionInstallUI::Delegate, |
| 68 public base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate> { |
| 69 public: |
| 70 ExtensionDisabledDialogDelegate(Profile* profile, |
| 71 ExtensionService* service, |
| 72 const Extension* extension); |
| 73 |
| 74 private: |
| 75 friend class base::RefCountedThreadSafe<ExtensionDisabledDialogDelegate>; |
| 76 |
| 77 virtual ~ExtensionDisabledDialogDelegate(); |
| 78 |
| 79 // ExtensionInstallUI::Delegate: |
| 80 virtual void InstallUIProceed() OVERRIDE; |
| 81 virtual void InstallUIAbort(bool user_initiated) OVERRIDE; |
| 82 |
| 83 // The UI for showing the install dialog when enabling. |
| 84 scoped_ptr<ExtensionInstallUI> install_ui_; |
| 85 |
| 86 ExtensionService* service_; |
| 87 const Extension* extension_; |
| 88 }; |
| 89 |
| 90 ExtensionDisabledDialogDelegate::ExtensionDisabledDialogDelegate( |
| 91 Profile* profile, |
| 92 ExtensionService* service, |
| 93 const Extension* extension) |
| 94 : service_(service), extension_(extension) { |
| 95 AddRef(); // Balanced in Proceed or Abort. |
| 96 |
| 97 install_ui_.reset(new ExtensionInstallUI(profile)); |
| 98 install_ui_->ConfirmReEnable(this, extension_); |
| 99 } |
| 100 |
| 101 ExtensionDisabledDialogDelegate::~ExtensionDisabledDialogDelegate() { |
| 102 } |
| 103 |
| 104 void ExtensionDisabledDialogDelegate::InstallUIProceed() { |
| 105 service_->GrantPermissionsAndEnableExtension(extension_); |
| 106 Release(); |
| 107 } |
| 108 |
| 109 void ExtensionDisabledDialogDelegate::InstallUIAbort(bool user_initiated) { |
| 110 std::string histogram_name = user_initiated ? |
| 111 "Extensions.Permissions_ReEnableCancel" : |
| 112 "Extensions.Permissions_ReEnableAbort"; |
| 113 ExtensionService::RecordPermissionMessagesHistogram( |
| 114 extension_, histogram_name.c_str()); |
| 115 |
| 116 // Do nothing. The extension will remain disabled. |
| 117 Release(); |
| 118 } |
| 119 |
| 120 // ExtensionDisabledGlobalError ----------------------------------------------- |
| 121 |
| 122 class ExtensionDisabledGlobalError : public GlobalError, |
| 123 public content::NotificationObserver, |
| 124 public ExtensionUninstallDialog::Delegate { |
| 125 public: |
| 126 ExtensionDisabledGlobalError(ExtensionService* service, |
| 127 const Extension* extension); |
| 128 virtual ~ExtensionDisabledGlobalError(); |
| 129 |
| 130 // GlobalError implementation. |
| 131 virtual bool HasBadge() OVERRIDE; |
| 132 virtual bool HasMenuItem() OVERRIDE; |
| 133 virtual int MenuItemCommandID() OVERRIDE; |
| 134 virtual string16 MenuItemLabel() OVERRIDE; |
| 135 virtual void ExecuteMenuItem(Browser* browser) OVERRIDE; |
| 136 virtual bool HasBubbleView() OVERRIDE; |
| 137 virtual string16 GetBubbleViewTitle() OVERRIDE; |
| 138 virtual string16 GetBubbleViewMessage() OVERRIDE; |
| 139 virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE; |
| 140 virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE; |
| 141 virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE; |
| 142 virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE; |
| 143 virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE; |
| 144 |
| 145 // ExtensionUninstallDialog::Delegate implementation. |
| 146 virtual void ExtensionUninstallAccepted() OVERRIDE; |
| 147 virtual void ExtensionUninstallCanceled() OVERRIDE; |
| 148 |
| 149 // content::NotificationObserver implementation. |
| 150 virtual void Observe(int type, |
| 151 const content::NotificationSource& source, |
| 152 const content::NotificationDetails& details) OVERRIDE; |
| 153 |
| 154 private: |
| 155 ExtensionService* service_; |
| 156 const Extension* extension_; |
| 157 |
| 158 scoped_ptr<ExtensionUninstallDialog> uninstall_dialog_; |
| 159 |
| 160 // Menu command ID assigned for this extension's error. |
| 161 int menu_command_id_; |
| 162 |
| 163 content::NotificationRegistrar registrar_; |
| 164 }; |
| 165 |
| 166 // TODO(yoz): create error at startup for disabled extensions. |
| 167 ExtensionDisabledGlobalError::ExtensionDisabledGlobalError( |
| 168 ExtensionService* service, |
| 169 const Extension* extension) |
| 170 : service_(service), |
| 171 extension_(extension), |
| 172 menu_command_id_(GetMenuCommandID()) { |
| 173 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
| 174 content::Source<Profile>(service->profile())); |
| 175 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 176 content::Source<Profile>(service->profile())); |
| 177 } |
| 178 |
| 179 ExtensionDisabledGlobalError::~ExtensionDisabledGlobalError() { |
| 180 } |
| 181 |
| 182 bool ExtensionDisabledGlobalError::HasBadge() { |
| 183 return true; |
| 184 } |
| 185 |
| 186 bool ExtensionDisabledGlobalError::HasMenuItem() { |
| 187 return true; |
| 188 } |
| 189 |
| 190 int ExtensionDisabledGlobalError::MenuItemCommandID() { |
| 191 return menu_command_id_; |
| 192 } |
| 193 |
| 194 string16 ExtensionDisabledGlobalError::MenuItemLabel() { |
| 195 return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_ERROR_TITLE, |
| 196 UTF8ToUTF16(extension_->name())); |
| 197 } |
| 198 |
| 199 void ExtensionDisabledGlobalError::ExecuteMenuItem(Browser* browser) { |
| 200 ShowBubbleView(browser); |
| 201 } |
| 202 |
| 203 bool ExtensionDisabledGlobalError::HasBubbleView() { |
| 204 return true; |
| 205 } |
| 206 |
| 207 string16 ExtensionDisabledGlobalError::GetBubbleViewTitle() { |
| 208 return l10n_util::GetStringFUTF16(IDS_EXTENSION_DISABLED_ERROR_TITLE, |
| 209 UTF8ToUTF16(extension_->name())); |
| 210 } |
| 211 |
| 212 string16 ExtensionDisabledGlobalError::GetBubbleViewMessage() { |
| 213 return l10n_util::GetStringFUTF16(extension_->is_app() ? |
| 214 IDS_APP_DISABLED_ERROR_LABEL : IDS_EXTENSION_DISABLED_ERROR_LABEL, |
| 215 UTF8ToUTF16(extension_->name())); |
| 216 } |
| 217 |
| 218 string16 ExtensionDisabledGlobalError::GetBubbleViewAcceptButtonLabel() { |
| 219 return l10n_util::GetStringUTF16( |
| 220 IDS_EXTENSION_DISABLED_ERROR_ENABLE_BUTTON); |
| 221 } |
| 222 |
| 223 string16 ExtensionDisabledGlobalError::GetBubbleViewCancelButtonLabel() { |
| 224 return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL); |
| 225 } |
| 226 |
| 227 void ExtensionDisabledGlobalError::OnBubbleViewDidClose(Browser* browser) { |
| 228 } |
| 229 |
| 230 void ExtensionDisabledGlobalError::BubbleViewAcceptButtonPressed( |
| 231 Browser* browser) { |
| 232 new ExtensionDisabledDialogDelegate(service_->profile(), service_, |
| 233 extension_); |
| 234 } |
| 235 |
| 236 void ExtensionDisabledGlobalError::BubbleViewCancelButtonPressed( |
| 237 Browser* browser) { |
| 238 uninstall_dialog_.reset( |
| 239 ExtensionUninstallDialog::Create(service_->profile(), this)); |
| 240 uninstall_dialog_->ConfirmUninstall(extension_); |
| 241 } |
| 242 |
| 243 void ExtensionDisabledGlobalError::ExtensionUninstallAccepted() { |
| 244 service_->UninstallExtension(extension_->id(), false, NULL); |
| 245 } |
| 246 |
| 247 void ExtensionDisabledGlobalError::ExtensionUninstallCanceled() { |
| 248 // Nothing happens, and the error is still there. |
| 249 } |
| 250 |
| 251 void ExtensionDisabledGlobalError::Observe( |
| 252 int type, |
| 253 const content::NotificationSource& source, |
| 254 const content::NotificationDetails& details) { |
| 255 const Extension* extension = NULL; |
| 256 // The error is invalidated if the extension has been reloaded |
| 257 // or unloaded. |
| 258 if (type == chrome::NOTIFICATION_EXTENSION_LOADED) { |
| 259 extension = content::Details<const Extension>(details).ptr(); |
| 260 } else { |
| 261 DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNLOADED, type); |
| 262 UnloadedExtensionInfo* info = |
| 263 content::Details<UnloadedExtensionInfo>(details).ptr(); |
| 264 extension = info->extension; |
| 265 } |
| 266 if (extension == extension_) { |
| 267 GlobalErrorServiceFactory::GetForProfile(service_->profile())-> |
| 268 RemoveGlobalError(this); |
| 269 ReleaseMenuCommandID(menu_command_id_); |
| 270 delete this; |
| 271 } |
| 272 } |
| 273 |
| 274 // Globals -------------------------------------------------------------------- |
| 275 |
| 276 namespace extensions { |
| 277 |
| 278 void ShowExtensionDisabledUI(ExtensionService* service, |
| 279 Profile* profile, |
| 280 const Extension* extension) { |
| 281 GlobalErrorServiceFactory::GetForProfile(service->profile())-> |
| 282 AddGlobalError(new ExtensionDisabledGlobalError(service, extension)); |
| 283 } |
| 284 |
| 285 void ShowExtensionDisabledDialog(ExtensionService* service, Profile* profile, |
| 286 const Extension* extension) { |
| 287 // This object manages its own lifetime. |
| 288 new ExtensionDisabledDialogDelegate(profile, service, extension); |
| 289 } |
| 290 |
| 291 } // namespace extensions |
| OLD | NEW |