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/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" |
| 18 #include "chrome/browser/extensions/extension_service.h" |
| 19 #include "chrome/browser/extensions/extension_uninstall_dialog.h" |
| 20 #include "chrome/browser/profiles/profile.h" |
| 21 #include "chrome/browser/ui/browser.h" |
| 22 #include "chrome/browser/ui/global_error/global_error.h" |
| 23 #include "chrome/browser/ui/global_error/global_error_service.h" |
| 24 #include "chrome/browser/ui/global_error/global_error_service_factory.h" |
| 25 #include "chrome/common/chrome_notification_types.h" |
| 26 #include "chrome/common/extensions/extension.h" |
| 27 #include "content/public/browser/notification_details.h" |
| 28 #include "content/public/browser/notification_observer.h" |
| 29 #include "content/public/browser/notification_registrar.h" |
| 30 #include "content/public/browser/notification_source.h" |
| 31 #include "grit/chromium_strings.h" |
| 32 #include "grit/generated_resources.h" |
| 33 #include "grit/theme_resources.h" |
| 34 #include "ui/base/l10n/l10n_util.h" |
| 35 |
| 36 namespace extensions { |
| 37 |
| 38 static const int kMenuCommandId = IDC_EXTERNAL_EXTENSION_ALERT; |
| 39 |
| 40 // ExternalInstallDialogDelegate -------------------------------------------- |
| 41 |
| 42 // TODO(mpcomplete): Get rid of the refcounting on this class, or document |
| 43 // why it's necessary. Will do after refactoring to merge back with |
| 44 // ExtensionDisabledDialogDelegate. |
| 45 class ExternalInstallDialogDelegate |
| 46 : public ExtensionInstallPrompt::Delegate, |
| 47 public base::RefCountedThreadSafe<ExternalInstallDialogDelegate> { |
| 48 public: |
| 49 ExternalInstallDialogDelegate(Browser* browser, |
| 50 ExtensionService* service, |
| 51 const Extension* extension); |
| 52 |
| 53 private: |
| 54 friend class base::RefCountedThreadSafe<ExternalInstallDialogDelegate>; |
| 55 |
| 56 virtual ~ExternalInstallDialogDelegate(); |
| 57 |
| 58 // ExtensionInstallPrompt::Delegate: |
| 59 virtual void InstallUIProceed() OVERRIDE; |
| 60 virtual void InstallUIAbort(bool user_initiated) OVERRIDE; |
| 61 |
| 62 // The UI for showing the install dialog when enabling. |
| 63 scoped_ptr<ExtensionInstallPrompt> install_ui_; |
| 64 |
| 65 ExtensionService* service_; |
| 66 const Extension* extension_; |
| 67 }; |
| 68 |
| 69 ExternalInstallDialogDelegate::ExternalInstallDialogDelegate( |
| 70 Browser* browser, |
| 71 ExtensionService* service, |
| 72 const Extension* extension) |
| 73 : service_(service), extension_(extension) { |
| 74 AddRef(); // Balanced in Proceed or Abort. |
| 75 |
| 76 install_ui_.reset(chrome::CreateExtensionInstallPromptWithBrowser(browser)); |
| 77 install_ui_->ConfirmExternalInstall(this, extension_); |
| 78 } |
| 79 |
| 80 ExternalInstallDialogDelegate::~ExternalInstallDialogDelegate() { |
| 81 } |
| 82 |
| 83 void ExternalInstallDialogDelegate::InstallUIProceed() { |
| 84 service_->GrantPermissionsAndEnableExtension( |
| 85 extension_, install_ui_->record_oauth2_grant()); |
| 86 Release(); |
| 87 } |
| 88 |
| 89 void ExternalInstallDialogDelegate::InstallUIAbort(bool user_initiated) { |
| 90 service_->UninstallExtension(extension_->id(), false, NULL); |
| 91 Release(); |
| 92 } |
| 93 |
| 94 static void ShowExternalInstallDialog(ExtensionService* service, |
| 95 Browser* browser, |
| 96 const Extension* extension) { |
| 97 // This object manages its own lifetime. |
| 98 new ExternalInstallDialogDelegate(browser, service, extension); |
| 99 } |
| 100 |
| 101 // ExternalInstallGlobalError ----------------------------------------------- |
| 102 |
| 103 class ExternalInstallGlobalError : public GlobalError, |
| 104 public content::NotificationObserver { |
| 105 public: |
| 106 ExternalInstallGlobalError(ExtensionService* service, |
| 107 const Extension* extension); |
| 108 virtual ~ExternalInstallGlobalError(); |
| 109 |
| 110 const Extension* extension() const { return extension_; } |
| 111 |
| 112 // GlobalError implementation. |
| 113 virtual bool HasBadge() OVERRIDE; |
| 114 virtual int GetBadgeResourceID() OVERRIDE; |
| 115 virtual bool HasMenuItem() OVERRIDE; |
| 116 virtual int MenuItemCommandID() OVERRIDE; |
| 117 virtual string16 MenuItemLabel() OVERRIDE; |
| 118 virtual int MenuItemIconResourceID() OVERRIDE; |
| 119 virtual void ExecuteMenuItem(Browser* browser) OVERRIDE; |
| 120 virtual bool HasBubbleView() OVERRIDE; |
| 121 virtual string16 GetBubbleViewTitle() OVERRIDE; |
| 122 virtual string16 GetBubbleViewMessage() OVERRIDE; |
| 123 virtual string16 GetBubbleViewAcceptButtonLabel() OVERRIDE; |
| 124 virtual string16 GetBubbleViewCancelButtonLabel() OVERRIDE; |
| 125 virtual void OnBubbleViewDidClose(Browser* browser) OVERRIDE; |
| 126 virtual void BubbleViewAcceptButtonPressed(Browser* browser) OVERRIDE; |
| 127 virtual void BubbleViewCancelButtonPressed(Browser* browser) OVERRIDE; |
| 128 |
| 129 // content::NotificationObserver implementation. |
| 130 virtual void Observe(int type, |
| 131 const content::NotificationSource& source, |
| 132 const content::NotificationDetails& details) OVERRIDE; |
| 133 |
| 134 private: |
| 135 ExtensionService* service_; |
| 136 const Extension* extension_; |
| 137 |
| 138 // How the user responded to the error; used for metrics. |
| 139 enum UserResponse { |
| 140 IGNORED, |
| 141 REENABLE, |
| 142 UNINSTALL, |
| 143 USER_RESPONSE_BUCKET_BOUNDARY |
| 144 }; |
| 145 UserResponse user_response_; |
| 146 |
| 147 content::NotificationRegistrar registrar_; |
| 148 }; |
| 149 |
| 150 ExternalInstallGlobalError::ExternalInstallGlobalError( |
| 151 ExtensionService* service, |
| 152 const Extension* extension) |
| 153 : service_(service), |
| 154 extension_(extension), |
| 155 user_response_(IGNORED) { |
| 156 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
| 157 content::Source<Profile>(service->profile())); |
| 158 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| 159 content::Source<Profile>(service->profile())); |
| 160 } |
| 161 |
| 162 ExternalInstallGlobalError::~ExternalInstallGlobalError() { |
| 163 HISTOGRAM_ENUMERATION("Extensions.ExternalInstallUIUserResponse", |
| 164 user_response_, USER_RESPONSE_BUCKET_BOUNDARY); |
| 165 } |
| 166 |
| 167 bool ExternalInstallGlobalError::HasBadge() { |
| 168 return true; |
| 169 } |
| 170 |
| 171 int ExternalInstallGlobalError::GetBadgeResourceID() { |
| 172 return IDR_UPDATE_BADGE_EXTENSION; |
| 173 } |
| 174 |
| 175 bool ExternalInstallGlobalError::HasMenuItem() { |
| 176 return true; |
| 177 } |
| 178 |
| 179 int ExternalInstallGlobalError::MenuItemCommandID() { |
| 180 return kMenuCommandId; |
| 181 } |
| 182 |
| 183 int ExternalInstallGlobalError::MenuItemIconResourceID() { |
| 184 return IDR_UPDATE_MENU_EXTENSION; |
| 185 } |
| 186 |
| 187 string16 ExternalInstallGlobalError::MenuItemLabel() { |
| 188 return l10n_util::GetStringFUTF16(IDS_EXTENSION_EXTERNAL_INSTALL_ALERT, |
| 189 UTF8ToUTF16(extension_->name())); |
| 190 } |
| 191 |
| 192 void ExternalInstallGlobalError::ExecuteMenuItem(Browser* browser) { |
| 193 ShowExternalInstallDialog(service_, browser, extension_); |
| 194 } |
| 195 |
| 196 bool ExternalInstallGlobalError::HasBubbleView() { |
| 197 return false; |
| 198 } |
| 199 |
| 200 string16 ExternalInstallGlobalError::GetBubbleViewTitle() { |
| 201 return string16(); |
| 202 } |
| 203 |
| 204 string16 ExternalInstallGlobalError::GetBubbleViewMessage() { |
| 205 return string16(); |
| 206 } |
| 207 |
| 208 string16 ExternalInstallGlobalError::GetBubbleViewAcceptButtonLabel() { |
| 209 return string16(); |
| 210 } |
| 211 |
| 212 string16 ExternalInstallGlobalError::GetBubbleViewCancelButtonLabel() { |
| 213 return string16(); |
| 214 } |
| 215 |
| 216 void ExternalInstallGlobalError::OnBubbleViewDidClose(Browser* browser) { |
| 217 NOTREACHED(); |
| 218 } |
| 219 |
| 220 void ExternalInstallGlobalError::BubbleViewAcceptButtonPressed( |
| 221 Browser* browser) { |
| 222 NOTREACHED(); |
| 223 } |
| 224 |
| 225 void ExternalInstallGlobalError::BubbleViewCancelButtonPressed( |
| 226 Browser* browser) { |
| 227 NOTREACHED(); |
| 228 } |
| 229 |
| 230 void ExternalInstallGlobalError::Observe( |
| 231 int type, |
| 232 const content::NotificationSource& source, |
| 233 const content::NotificationDetails& details) { |
| 234 const Extension* extension = NULL; |
| 235 // The error is invalidated if the extension has been reloaded |
| 236 // or unloaded. |
| 237 if (type == chrome::NOTIFICATION_EXTENSION_LOADED) { |
| 238 extension = content::Details<const Extension>(details).ptr(); |
| 239 } else { |
| 240 DCHECK_EQ(chrome::NOTIFICATION_EXTENSION_UNLOADED, type); |
| 241 extensions::UnloadedExtensionInfo* info = |
| 242 content::Details<extensions::UnloadedExtensionInfo>(details).ptr(); |
| 243 extension = info->extension; |
| 244 } |
| 245 if (extension == extension_) { |
| 246 GlobalErrorService* error_service = |
| 247 GlobalErrorServiceFactory::GetForProfile(service_->profile()); |
| 248 error_service->RemoveGlobalError(this); |
| 249 |
| 250 // We only check for new external installs on startup, so these |
| 251 // notifications are guaranteed to be user-initiated. |
| 252 if (type == chrome::NOTIFICATION_EXTENSION_LOADED) |
| 253 user_response_ = REENABLE; |
| 254 else if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) |
| 255 user_response_ = UNINSTALL; |
| 256 |
| 257 service_->AcknowledgeExternalExtension(extension_->id()); |
| 258 delete this; |
| 259 } |
| 260 } |
| 261 |
| 262 // Public interface --------------------------------------------------------- |
| 263 |
| 264 bool AddExternalInstallError(ExtensionService* service, |
| 265 const Extension* extension) { |
| 266 GlobalErrorService* error_service = |
| 267 GlobalErrorServiceFactory::GetForProfile(service->profile()); |
| 268 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID( |
| 269 kMenuCommandId); |
| 270 if (error) |
| 271 return false; |
| 272 |
| 273 error_service->AddGlobalError( |
| 274 new ExternalInstallGlobalError(service, extension)); |
| 275 return true; |
| 276 } |
| 277 |
| 278 void RemoveExternalInstallError(ExtensionService* service) { |
| 279 GlobalErrorService* error_service = |
| 280 GlobalErrorServiceFactory::GetForProfile(service->profile()); |
| 281 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID( |
| 282 kMenuCommandId); |
| 283 if (error) { |
| 284 error_service->RemoveGlobalError(error); |
| 285 delete error; |
| 286 } |
| 287 } |
| 288 |
| 289 bool HasExternalInstallError(ExtensionService* service) { |
| 290 GlobalErrorService* error_service = |
| 291 GlobalErrorServiceFactory::GetForProfile(service->profile()); |
| 292 GlobalError* error = error_service->GetGlobalErrorByMenuItemCommandID( |
| 293 kMenuCommandId); |
| 294 return !!error; |
| 295 } |
| 296 |
| 297 } // namespace extensions |
OLD | NEW |