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/plugins/plugin_infobar_delegates.h" 6 7 #include "base/bind.h" 8 #include "base/path_service.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "chrome/browser/content_settings/host_content_settings_map.h" 11 #include "chrome/browser/infobars/infobar_service.h" 12 #include "chrome/browser/lifetime/application_lifetime.h" 13 #include "chrome/browser/plugins/chrome_plugin_service_filter.h" 14 #include "chrome/browser/plugins/plugin_metadata.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/shell_integration.h" 17 #include "chrome/browser/ui/browser_commands.h" 18 #include "chrome/common/url_constants.h" 19 #include "components/google/core/browser/google_util.h" 20 #include "components/infobars/core/infobar.h" 21 #include "content/public/browser/render_process_host.h" 22 #include "content/public/browser/render_view_host.h" 23 #include "content/public/browser/user_metrics.h" 24 #include "content/public/browser/web_contents.h" 25 #include "grit/generated_resources.h" 26 #include "grit/locale_settings.h" 27 #include "grit/theme_resources.h" 28 #include "ui/base/l10n/l10n_util.h" 29 30 #if defined(ENABLE_PLUGIN_INSTALLATION) 31 #if defined(OS_WIN) 32 #include "base/win/metro.h" 33 #endif 34 #include "chrome/browser/plugins/plugin_installer.h" 35 #endif 36 37 #if defined(OS_WIN) 38 #include <shellapi.h> 39 #include "ui/base/win/shell.h" 40 41 #if defined(USE_AURA) 42 #include "ui/aura/remote_window_tree_host_win.h" 43 #endif 44 #endif 45 46 using base::UserMetricsAction; 47 48 49 // PluginInfoBarDelegate ------------------------------------------------------ 50 51 PluginInfoBarDelegate::PluginInfoBarDelegate(const std::string& identifier) 52 : ConfirmInfoBarDelegate(), 53 identifier_(identifier) { 54 } 55 56 PluginInfoBarDelegate::~PluginInfoBarDelegate() { 57 } 58 59 bool PluginInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) { 60 InfoBarService::WebContentsFromInfoBar(infobar())->OpenURL( 61 content::OpenURLParams( 62 GURL(GetLearnMoreURL()), content::Referrer(), 63 (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, 64 content::PAGE_TRANSITION_LINK, false)); 65 return false; 66 } 67 68 void PluginInfoBarDelegate::LoadBlockedPlugins() { 69 content::WebContents* web_contents = 70 InfoBarService::WebContentsFromInfoBar(infobar()); 71 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( 72 web_contents, true, identifier_); 73 } 74 75 int PluginInfoBarDelegate::GetIconID() const { 76 return IDR_INFOBAR_PLUGIN_INSTALL; 77 } 78 79 base::string16 PluginInfoBarDelegate::GetLinkText() const { 80 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); 81 } 82 83 84 // UnauthorizedPluginInfoBarDelegate ------------------------------------------ 85 86 // static 87 void UnauthorizedPluginInfoBarDelegate::Create( 88 InfoBarService* infobar_service, 89 HostContentSettingsMap* content_settings, 90 const base::string16& name, 91 const std::string& identifier) { 92 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( 93 scoped_ptr<ConfirmInfoBarDelegate>(new UnauthorizedPluginInfoBarDelegate( 94 content_settings, name, identifier)))); 95 96 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Shown")); 97 std::string utf8_name(base::UTF16ToUTF8(name)); 98 if (utf8_name == PluginMetadata::kJavaGroupName) { 99 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Shown.Java")); 100 } else if (utf8_name == PluginMetadata::kQuickTimeGroupName) { 101 content::RecordAction( 102 UserMetricsAction("BlockedPluginInfobar.Shown.QuickTime")); 103 } else if (utf8_name == PluginMetadata::kShockwaveGroupName) { 104 content::RecordAction( 105 UserMetricsAction("BlockedPluginInfobar.Shown.Shockwave")); 106 } else if (utf8_name == PluginMetadata::kRealPlayerGroupName) { 107 content::RecordAction( 108 UserMetricsAction("BlockedPluginInfobar.Shown.RealPlayer")); 109 } else if (utf8_name == PluginMetadata::kWindowsMediaPlayerGroupName) { 110 content::RecordAction( 111 UserMetricsAction("BlockedPluginInfobar.Shown.WindowsMediaPlayer")); 112 } 113 } 114 115 UnauthorizedPluginInfoBarDelegate::UnauthorizedPluginInfoBarDelegate( 116 HostContentSettingsMap* content_settings, 117 const base::string16& name, 118 const std::string& identifier) 119 : PluginInfoBarDelegate(identifier), 120 content_settings_(content_settings), 121 name_(name) { 122 } 123 124 UnauthorizedPluginInfoBarDelegate::~UnauthorizedPluginInfoBarDelegate() { 125 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Closed")); 126 } 127 128 std::string UnauthorizedPluginInfoBarDelegate::GetLearnMoreURL() const { 129 return chrome::kBlockedPluginLearnMoreURL; 130 } 131 132 base::string16 UnauthorizedPluginInfoBarDelegate::GetMessageText() const { 133 return l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, name_); 134 } 135 136 base::string16 UnauthorizedPluginInfoBarDelegate::GetButtonLabel( 137 InfoBarButton button) const { 138 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 139 IDS_PLUGIN_ENABLE_TEMPORARILY : IDS_PLUGIN_ENABLE_ALWAYS); 140 } 141 142 bool UnauthorizedPluginInfoBarDelegate::Accept() { 143 content::RecordAction( 144 UserMetricsAction("BlockedPluginInfobar.AllowThisTime")); 145 LoadBlockedPlugins(); 146 return true; 147 } 148 149 bool UnauthorizedPluginInfoBarDelegate::Cancel() { 150 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.AlwaysAllow")); 151 const GURL& url = InfoBarService::WebContentsFromInfoBar(infobar())->GetURL(); 152 content_settings_->AddExceptionForURL(url, url, CONTENT_SETTINGS_TYPE_PLUGINS, 153 CONTENT_SETTING_ALLOW); 154 LoadBlockedPlugins(); 155 return true; 156 } 157 158 void UnauthorizedPluginInfoBarDelegate::InfoBarDismissed() { 159 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Dismissed")); 160 } 161 162 bool UnauthorizedPluginInfoBarDelegate::LinkClicked( 163 WindowOpenDisposition disposition) { 164 content::RecordAction(UserMetricsAction("BlockedPluginInfobar.LearnMore")); 165 return PluginInfoBarDelegate::LinkClicked(disposition); 166 } 167 168 169 #if defined(ENABLE_PLUGIN_INSTALLATION) 170 171 // OutdatedPluginInfoBarDelegate ---------------------------------------------- 172 173 void OutdatedPluginInfoBarDelegate::Create( 174 InfoBarService* infobar_service, 175 PluginInstaller* installer, 176 scoped_ptr<PluginMetadata> plugin_metadata) { 177 // Copy the name out of |plugin_metadata| now, since the Pass() call below 178 // will make it impossible to get at. 179 base::string16 name(plugin_metadata->name()); 180 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( 181 scoped_ptr<ConfirmInfoBarDelegate>(new OutdatedPluginInfoBarDelegate( 182 installer, plugin_metadata.Pass(), l10n_util::GetStringFUTF16( 183 (installer->state() == PluginInstaller::INSTALLER_STATE_IDLE) ? 184 IDS_PLUGIN_OUTDATED_PROMPT : IDS_PLUGIN_DOWNLOADING, 185 name))))); 186 } 187 188 OutdatedPluginInfoBarDelegate::OutdatedPluginInfoBarDelegate( 189 PluginInstaller* installer, 190 scoped_ptr<PluginMetadata> plugin_metadata, 191 const base::string16& message) 192 : PluginInfoBarDelegate(plugin_metadata->identifier()), 193 WeakPluginInstallerObserver(installer), 194 plugin_metadata_(plugin_metadata.Pass()), 195 message_(message) { 196 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Shown")); 197 std::string name = base::UTF16ToUTF8(plugin_metadata_->name()); 198 if (name == PluginMetadata::kJavaGroupName) { 199 content::RecordAction( 200 UserMetricsAction("OutdatedPluginInfobar.Shown.Java")); 201 } else if (name == PluginMetadata::kQuickTimeGroupName) { 202 content::RecordAction( 203 UserMetricsAction("OutdatedPluginInfobar.Shown.QuickTime")); 204 } else if (name == PluginMetadata::kShockwaveGroupName) { 205 content::RecordAction( 206 UserMetricsAction("OutdatedPluginInfobar.Shown.Shockwave")); 207 } else if (name == PluginMetadata::kRealPlayerGroupName) { 208 content::RecordAction( 209 UserMetricsAction("OutdatedPluginInfobar.Shown.RealPlayer")); 210 } else if (name == PluginMetadata::kSilverlightGroupName) { 211 content::RecordAction( 212 UserMetricsAction("OutdatedPluginInfobar.Shown.Silverlight")); 213 } else if (name == PluginMetadata::kAdobeReaderGroupName) { 214 content::RecordAction( 215 UserMetricsAction("OutdatedPluginInfobar.Shown.Reader")); 216 } 217 } 218 219 OutdatedPluginInfoBarDelegate::~OutdatedPluginInfoBarDelegate() { 220 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Closed")); 221 } 222 223 std::string OutdatedPluginInfoBarDelegate::GetLearnMoreURL() const { 224 return chrome::kOutdatedPluginLearnMoreURL; 225 } 226 227 base::string16 OutdatedPluginInfoBarDelegate::GetMessageText() const { 228 return message_; 229 } 230 231 base::string16 OutdatedPluginInfoBarDelegate::GetButtonLabel( 232 InfoBarButton button) const { 233 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 234 IDS_PLUGIN_UPDATE : IDS_PLUGIN_ENABLE_TEMPORARILY); 235 } 236 237 bool OutdatedPluginInfoBarDelegate::Accept() { 238 DCHECK_EQ(PluginInstaller::INSTALLER_STATE_IDLE, installer()->state()); 239 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Update")); 240 // A call to any of |OpenDownloadURL()| or |StartInstalling()| will 241 // result in deleting ourselves. Accordingly, we make sure to 242 // not pass a reference to an object that can go away. 243 GURL plugin_url(plugin_metadata_->plugin_url()); 244 content::WebContents* web_contents = 245 InfoBarService::WebContentsFromInfoBar(infobar()); 246 if (plugin_metadata_->url_for_display()) 247 installer()->OpenDownloadURL(plugin_url, web_contents); 248 else 249 installer()->StartInstalling(plugin_url, web_contents); 250 return false; 251 } 252 253 bool OutdatedPluginInfoBarDelegate::Cancel() { 254 content::RecordAction( 255 UserMetricsAction("OutdatedPluginInfobar.AllowThisTime")); 256 LoadBlockedPlugins(); 257 return true; 258 } 259 260 void OutdatedPluginInfoBarDelegate::InfoBarDismissed() { 261 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Dismissed")); 262 } 263 264 bool OutdatedPluginInfoBarDelegate::LinkClicked( 265 WindowOpenDisposition disposition) { 266 content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.LearnMore")); 267 return PluginInfoBarDelegate::LinkClicked(disposition); 268 } 269 270 void OutdatedPluginInfoBarDelegate::DownloadStarted() { 271 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, 272 plugin_metadata_->name())); 273 } 274 275 void OutdatedPluginInfoBarDelegate::DownloadError(const std::string& message) { 276 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT, 277 plugin_metadata_->name())); 278 } 279 280 void OutdatedPluginInfoBarDelegate::DownloadCancelled() { 281 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED, 282 plugin_metadata_->name())); 283 } 284 285 void OutdatedPluginInfoBarDelegate::DownloadFinished() { 286 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_UPDATING, 287 plugin_metadata_->name())); 288 } 289 290 void OutdatedPluginInfoBarDelegate::OnlyWeakObserversLeft() { 291 infobar()->RemoveSelf(); 292 } 293 294 void OutdatedPluginInfoBarDelegate::ReplaceWithInfoBar( 295 const base::string16& message) { 296 // Return early if the message doesn't change. This is important in case the 297 // PluginInstaller is still iterating over its observers (otherwise we would 298 // keep replacing infobar delegates infinitely). 299 if ((message_ == message) || !infobar()->owner()) 300 return; 301 PluginInstallerInfoBarDelegate::Replace( 302 infobar(), installer(), plugin_metadata_->Clone(), false, message); 303 } 304 305 306 // PluginInstallerInfoBarDelegate --------------------------------------------- 307 308 void PluginInstallerInfoBarDelegate::Create( 309 InfoBarService* infobar_service, 310 PluginInstaller* installer, 311 scoped_ptr<PluginMetadata> plugin_metadata, 312 const InstallCallback& callback) { 313 base::string16 name(plugin_metadata->name()); 314 #if defined(OS_WIN) 315 if (base::win::IsMetroProcess()) { 316 PluginMetroModeInfoBarDelegate::Create( 317 infobar_service, PluginMetroModeInfoBarDelegate::MISSING_PLUGIN, name); 318 return; 319 } 320 #endif 321 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( 322 scoped_ptr<ConfirmInfoBarDelegate>(new PluginInstallerInfoBarDelegate( 323 installer, plugin_metadata.Pass(), callback, true, 324 l10n_util::GetStringFUTF16( 325 (installer->state() == PluginInstaller::INSTALLER_STATE_IDLE) ? 326 IDS_PLUGININSTALLER_INSTALLPLUGIN_PROMPT : 327 IDS_PLUGIN_DOWNLOADING, 328 name))))); 329 } 330 331 void PluginInstallerInfoBarDelegate::Replace( 332 infobars::InfoBar* infobar, 333 PluginInstaller* installer, 334 scoped_ptr<PluginMetadata> plugin_metadata, 335 bool new_install, 336 const base::string16& message) { 337 DCHECK(infobar->owner()); 338 infobar->owner()->ReplaceInfoBar(infobar, 339 ConfirmInfoBarDelegate::CreateInfoBar(scoped_ptr<ConfirmInfoBarDelegate>( 340 new PluginInstallerInfoBarDelegate( 341 installer, plugin_metadata.Pass(), 342 PluginInstallerInfoBarDelegate::InstallCallback(), new_install, 343 message)))); 344 } 345 346 PluginInstallerInfoBarDelegate::PluginInstallerInfoBarDelegate( 347 PluginInstaller* installer, 348 scoped_ptr<PluginMetadata> plugin_metadata, 349 const InstallCallback& callback, 350 bool new_install, 351 const base::string16& message) 352 : ConfirmInfoBarDelegate(), 353 WeakPluginInstallerObserver(installer), 354 plugin_metadata_(plugin_metadata.Pass()), 355 callback_(callback), 356 new_install_(new_install), 357 message_(message) { 358 } 359 360 PluginInstallerInfoBarDelegate::~PluginInstallerInfoBarDelegate() { 361 } 362 363 int PluginInstallerInfoBarDelegate::GetIconID() const { 364 return IDR_INFOBAR_PLUGIN_INSTALL; 365 } 366 367 base::string16 PluginInstallerInfoBarDelegate::GetMessageText() const { 368 return message_; 369 } 370 371 int PluginInstallerInfoBarDelegate::GetButtons() const { 372 return callback_.is_null() ? BUTTON_NONE : BUTTON_OK; 373 } 374 375 base::string16 PluginInstallerInfoBarDelegate::GetButtonLabel( 376 InfoBarButton button) const { 377 DCHECK_EQ(BUTTON_OK, button); 378 return l10n_util::GetStringUTF16(IDS_PLUGININSTALLER_INSTALLPLUGIN_BUTTON); 379 } 380 381 bool PluginInstallerInfoBarDelegate::Accept() { 382 callback_.Run(plugin_metadata_.get()); 383 return false; 384 } 385 386 base::string16 PluginInstallerInfoBarDelegate::GetLinkText() const { 387 return l10n_util::GetStringUTF16(new_install_ ? 388 IDS_PLUGININSTALLER_PROBLEMSINSTALLING : 389 IDS_PLUGININSTALLER_PROBLEMSUPDATING); 390 } 391 392 bool PluginInstallerInfoBarDelegate::LinkClicked( 393 WindowOpenDisposition disposition) { 394 GURL url(plugin_metadata_->help_url()); 395 if (url.is_empty()) { 396 url = GURL( 397 "https://www.google.com/support/chrome/bin/answer.py?answer=142064"); 398 } 399 InfoBarService::WebContentsFromInfoBar(infobar())->OpenURL( 400 content::OpenURLParams( 401 url, content::Referrer(), 402 (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, 403 content::PAGE_TRANSITION_LINK, false)); 404 return false; 405 } 406 407 void PluginInstallerInfoBarDelegate::DownloadStarted() { 408 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING, 409 plugin_metadata_->name())); 410 } 411 412 void PluginInstallerInfoBarDelegate::DownloadCancelled() { 413 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED, 414 plugin_metadata_->name())); 415 } 416 417 void PluginInstallerInfoBarDelegate::DownloadError(const std::string& message) { 418 ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT, 419 plugin_metadata_->name())); 420 } 421 422 void PluginInstallerInfoBarDelegate::DownloadFinished() { 423 ReplaceWithInfoBar( 424 l10n_util::GetStringFUTF16( 425 new_install_ ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING, 426 plugin_metadata_->name())); 427 } 428 429 void PluginInstallerInfoBarDelegate::OnlyWeakObserversLeft() { 430 infobar()->RemoveSelf(); 431 } 432 433 void PluginInstallerInfoBarDelegate::ReplaceWithInfoBar( 434 const base::string16& message) { 435 // Return early if the message doesn't change. This is important in case the 436 // PluginInstaller is still iterating over its observers (otherwise we would 437 // keep replacing infobar delegates infinitely). 438 if ((message_ == message) || !infobar()->owner()) 439 return; 440 Replace(infobar(), installer(), plugin_metadata_->Clone(), new_install_, 441 message); 442 } 443 444 445 #if defined(OS_WIN) 446 447 // PluginMetroModeInfoBarDelegate --------------------------------------------- 448 449 // static 450 void PluginMetroModeInfoBarDelegate::Create( 451 InfoBarService* infobar_service, 452 PluginMetroModeInfoBarDelegate::Mode mode, 453 const base::string16& name) { 454 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( 455 scoped_ptr<ConfirmInfoBarDelegate>( 456 new PluginMetroModeInfoBarDelegate(mode, name)))); 457 } 458 459 PluginMetroModeInfoBarDelegate::PluginMetroModeInfoBarDelegate( 460 PluginMetroModeInfoBarDelegate::Mode mode, 461 const base::string16& name) 462 : ConfirmInfoBarDelegate(), 463 mode_(mode), 464 name_(name) { 465 } 466 467 PluginMetroModeInfoBarDelegate::~PluginMetroModeInfoBarDelegate() { 468 } 469 470 int PluginMetroModeInfoBarDelegate::GetIconID() const { 471 return IDR_INFOBAR_PLUGIN_INSTALL; 472 } 473 474 base::string16 PluginMetroModeInfoBarDelegate::GetMessageText() const { 475 return l10n_util::GetStringFUTF16((mode_ == MISSING_PLUGIN) ? 476 IDS_METRO_MISSING_PLUGIN_PROMPT : IDS_METRO_NPAPI_PLUGIN_PROMPT, name_); 477 } 478 479 int PluginMetroModeInfoBarDelegate::GetButtons() const { 480 return BUTTON_OK; 481 } 482 483 base::string16 PluginMetroModeInfoBarDelegate::GetButtonLabel( 484 InfoBarButton button) const { 485 #if defined(USE_AURA) && defined(USE_ASH) 486 return l10n_util::GetStringUTF16(IDS_WIN8_DESKTOP_RESTART); 487 #else 488 return l10n_util::GetStringUTF16((mode_ == MISSING_PLUGIN) ? 489 IDS_WIN8_DESKTOP_RESTART : IDS_WIN8_DESKTOP_OPEN); 490 #endif 491 } 492 493 #if defined(USE_AURA) && defined(USE_ASH) 494 void LaunchDesktopInstanceHelper(const base::string16& url) { 495 base::FilePath exe_path; 496 if (!PathService::Get(base::FILE_EXE, &exe_path)) 497 return; 498 base::FilePath shortcut_path( 499 ShellIntegration::GetStartMenuShortcut(exe_path)); 500 501 // Actually launching the process needs to happen in the metro viewer, 502 // otherwise it won't automatically transition to desktop. So we have 503 // to send an IPC to the viewer to do the ShellExecute. 504 aura::RemoteWindowTreeHostWin::Instance()->HandleOpenURLOnDesktop( 505 shortcut_path, url); 506 } 507 #endif 508 509 bool PluginMetroModeInfoBarDelegate::Accept() { 510 chrome::AttemptRestartToDesktopMode(); 511 return true; 512 } 513 514 base::string16 PluginMetroModeInfoBarDelegate::GetLinkText() const { 515 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); 516 } 517 518 bool PluginMetroModeInfoBarDelegate::LinkClicked( 519 WindowOpenDisposition disposition) { 520 // TODO(shrikant): We may need to change language a little at following 521 // support URLs. With new approach we will just restart for both missing 522 // and not missing mode. 523 InfoBarService::WebContentsFromInfoBar(infobar())->OpenURL( 524 content::OpenURLParams( 525 GURL((mode_ == MISSING_PLUGIN) ? 526 "https://support.google.com/chrome/?p=ib_display_in_desktop" : 527 "https://support.google.com/chrome/?p=ib_redirect_to_desktop"), 528 content::Referrer(), 529 (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition, 530 content::PAGE_TRANSITION_LINK, false)); 531 return false; 532 } 533 534 #endif // defined(OS_WIN) 535 536 #endif // defined(ENABLE_PLUGIN_INSTALLATION) 537