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