Home | History | Annotate | Download | only in plugins
      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/path_service.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "chrome/browser/content_settings/host_content_settings_map.h"
     10 #include "chrome/browser/google/google_util.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/render_messages.h"
     19 #include "chrome/common/url_constants.h"
     20 #include "content/public/browser/browser_thread.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 #endif
     41 
     42 using content::UserMetricsAction;
     43 
     44 
     45 // PluginInfoBarDelegate ------------------------------------------------------
     46 
     47 PluginInfoBarDelegate::PluginInfoBarDelegate(InfoBarService* infobar_service,
     48                                              const std::string& identifier)
     49     : ConfirmInfoBarDelegate(infobar_service),
     50       identifier_(identifier) {
     51 }
     52 
     53 PluginInfoBarDelegate::~PluginInfoBarDelegate() {
     54 }
     55 
     56 bool PluginInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
     57   web_contents()->OpenURL(content::OpenURLParams(
     58       GURL(GetLearnMoreURL()), content::Referrer(),
     59       (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
     60       content::PAGE_TRANSITION_LINK, false));
     61   return false;
     62 }
     63 
     64 void PluginInfoBarDelegate::LoadBlockedPlugins() {
     65   content::RenderViewHost* host = web_contents()->GetRenderViewHost();
     66   ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
     67       host->GetProcess()->GetID());
     68   host->Send(new ChromeViewMsg_LoadBlockedPlugins(
     69       host->GetRoutingID(), identifier_));
     70 }
     71 
     72 int PluginInfoBarDelegate::GetIconID() const {
     73   return IDR_INFOBAR_PLUGIN_INSTALL;
     74 }
     75 
     76 string16 PluginInfoBarDelegate::GetLinkText() const {
     77   return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
     78 }
     79 
     80 
     81 // UnauthorizedPluginInfoBarDelegate ------------------------------------------
     82 
     83 // static
     84 void UnauthorizedPluginInfoBarDelegate::Create(
     85     InfoBarService* infobar_service,
     86     HostContentSettingsMap* content_settings,
     87     const string16& name,
     88     const std::string& identifier) {
     89   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
     90       new UnauthorizedPluginInfoBarDelegate(infobar_service, content_settings,
     91                                             name, identifier)));
     92 
     93   content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Shown"));
     94   std::string utf8_name(UTF16ToUTF8(name));
     95   if (utf8_name == PluginMetadata::kJavaGroupName) {
     96     content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Shown.Java"));
     97   } else if (utf8_name == PluginMetadata::kQuickTimeGroupName) {
     98     content::RecordAction(
     99         UserMetricsAction("BlockedPluginInfobar.Shown.QuickTime"));
    100   } else if (utf8_name == PluginMetadata::kShockwaveGroupName) {
    101     content::RecordAction(
    102         UserMetricsAction("BlockedPluginInfobar.Shown.Shockwave"));
    103   } else if (utf8_name == PluginMetadata::kRealPlayerGroupName) {
    104     content::RecordAction(
    105         UserMetricsAction("BlockedPluginInfobar.Shown.RealPlayer"));
    106   } else if (utf8_name == PluginMetadata::kWindowsMediaPlayerGroupName) {
    107     content::RecordAction(
    108         UserMetricsAction("BlockedPluginInfobar.Shown.WindowsMediaPlayer"));
    109   }
    110 }
    111 
    112 UnauthorizedPluginInfoBarDelegate::UnauthorizedPluginInfoBarDelegate(
    113     InfoBarService* infobar_service,
    114     HostContentSettingsMap* content_settings,
    115     const string16& name,
    116     const std::string& identifier)
    117     : PluginInfoBarDelegate(infobar_service, identifier),
    118       content_settings_(content_settings),
    119       name_(name) {
    120 }
    121 
    122 UnauthorizedPluginInfoBarDelegate::~UnauthorizedPluginInfoBarDelegate() {
    123   content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Closed"));
    124 }
    125 
    126 std::string UnauthorizedPluginInfoBarDelegate::GetLearnMoreURL() const {
    127   return chrome::kBlockedPluginLearnMoreURL;
    128 }
    129 
    130 string16 UnauthorizedPluginInfoBarDelegate::GetMessageText() const {
    131   return l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, name_);
    132 }
    133 
    134 string16 UnauthorizedPluginInfoBarDelegate::GetButtonLabel(
    135     InfoBarButton button) const {
    136   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
    137       IDS_PLUGIN_ENABLE_TEMPORARILY : IDS_PLUGIN_ENABLE_ALWAYS);
    138 }
    139 
    140 bool UnauthorizedPluginInfoBarDelegate::Accept() {
    141   content::RecordAction(
    142       UserMetricsAction("BlockedPluginInfobar.AllowThisTime"));
    143   LoadBlockedPlugins();
    144   return true;
    145 }
    146 
    147 bool UnauthorizedPluginInfoBarDelegate::Cancel() {
    148   content::RecordAction(UserMetricsAction("BlockedPluginInfobar.AlwaysAllow"));
    149   const GURL& url = web_contents()->GetURL();
    150   content_settings_->AddExceptionForURL(url, url, CONTENT_SETTINGS_TYPE_PLUGINS,
    151                                         std::string(), CONTENT_SETTING_ALLOW);
    152   LoadBlockedPlugins();
    153   return true;
    154 }
    155 
    156 void UnauthorizedPluginInfoBarDelegate::InfoBarDismissed() {
    157   content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Dismissed"));
    158 }
    159 
    160 bool UnauthorizedPluginInfoBarDelegate::LinkClicked(
    161     WindowOpenDisposition disposition) {
    162   content::RecordAction(UserMetricsAction("BlockedPluginInfobar.LearnMore"));
    163   return PluginInfoBarDelegate::LinkClicked(disposition);
    164 }
    165 
    166 
    167 #if defined(ENABLE_PLUGIN_INSTALLATION)
    168 
    169 // OutdatedPluginInfoBarDelegate ----------------------------------------------
    170 
    171 void OutdatedPluginInfoBarDelegate::Create(
    172     InfoBarService* infobar_service,
    173     PluginInstaller* installer,
    174     scoped_ptr<PluginMetadata> plugin_metadata) {
    175   // Copy the name out of |plugin_metadata| now, since the Pass() call below
    176   // will make it impossible to get at.
    177   string16 name(plugin_metadata->name());
    178   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
    179       new OutdatedPluginInfoBarDelegate(
    180           infobar_service, installer, plugin_metadata.Pass(),
    181           l10n_util::GetStringFUTF16(
    182               (installer->state() == PluginInstaller::INSTALLER_STATE_IDLE) ?
    183                   IDS_PLUGIN_OUTDATED_PROMPT : IDS_PLUGIN_DOWNLOADING,
    184               name))));
    185 }
    186 
    187 OutdatedPluginInfoBarDelegate::OutdatedPluginInfoBarDelegate(
    188     InfoBarService* infobar_service,
    189     PluginInstaller* installer,
    190     scoped_ptr<PluginMetadata> plugin_metadata,
    191     const string16& message)
    192     : PluginInfoBarDelegate(infobar_service, 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 = 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 string16 OutdatedPluginInfoBarDelegate::GetMessageText() const {
    228   return message_;
    229 }
    230 
    231 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   if (plugin_metadata_->url_for_display())
    245     installer()->OpenDownloadURL(plugin_url, web_contents());
    246   else
    247     installer()->StartInstalling(plugin_url, web_contents());
    248   return false;
    249 }
    250 
    251 bool OutdatedPluginInfoBarDelegate::Cancel() {
    252   content::RecordAction(
    253       UserMetricsAction("OutdatedPluginInfobar.AllowThisTime"));
    254   LoadBlockedPlugins();
    255   return true;
    256 }
    257 
    258 void OutdatedPluginInfoBarDelegate::InfoBarDismissed() {
    259   content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Dismissed"));
    260 }
    261 
    262 bool OutdatedPluginInfoBarDelegate::LinkClicked(
    263     WindowOpenDisposition disposition) {
    264   content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.LearnMore"));
    265   return PluginInfoBarDelegate::LinkClicked(disposition);
    266 }
    267 
    268 void OutdatedPluginInfoBarDelegate::DownloadStarted() {
    269   ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING,
    270                                                 plugin_metadata_->name()));
    271 }
    272 
    273 void OutdatedPluginInfoBarDelegate::DownloadError(const std::string& message) {
    274   ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT,
    275                                                 plugin_metadata_->name()));
    276 }
    277 
    278 void OutdatedPluginInfoBarDelegate::DownloadCancelled() {
    279   ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED,
    280                                                 plugin_metadata_->name()));
    281 }
    282 
    283 void OutdatedPluginInfoBarDelegate::DownloadFinished() {
    284   ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_UPDATING,
    285                                                 plugin_metadata_->name()));
    286 }
    287 
    288 void OutdatedPluginInfoBarDelegate::OnlyWeakObserversLeft() {
    289   if (owner())
    290     owner()->RemoveInfoBar(this);
    291 }
    292 
    293 void OutdatedPluginInfoBarDelegate::ReplaceWithInfoBar(
    294     const string16& message) {
    295   // Return early if the message doesn't change. This is important in case the
    296   // PluginInstaller is still iterating over its observers (otherwise we would
    297   // keep replacing infobar delegates infinitely).
    298   if ((message_ == message) || !owner())
    299     return;
    300   PluginInstallerInfoBarDelegate::Replace(
    301       this, installer(), plugin_metadata_->Clone(), false, message);
    302 }
    303 
    304 
    305 // PluginInstallerInfoBarDelegate ---------------------------------------------
    306 
    307 void PluginInstallerInfoBarDelegate::Create(
    308     InfoBarService* infobar_service,
    309     PluginInstaller* installer,
    310     scoped_ptr<PluginMetadata> plugin_metadata,
    311     const InstallCallback& callback) {
    312   string16 name(plugin_metadata->name());
    313 #if defined(OS_WIN)
    314   if (base::win::IsMetroProcess()) {
    315     PluginMetroModeInfoBarDelegate::Create(
    316         infobar_service, PluginMetroModeInfoBarDelegate::MISSING_PLUGIN, name);
    317     return;
    318   }
    319 #endif
    320   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
    321       new PluginInstallerInfoBarDelegate(
    322           infobar_service, installer, plugin_metadata.Pass(), callback, true,
    323           l10n_util::GetStringFUTF16(
    324               (installer->state() == PluginInstaller::INSTALLER_STATE_IDLE) ?
    325                   IDS_PLUGININSTALLER_INSTALLPLUGIN_PROMPT :
    326                   IDS_PLUGIN_DOWNLOADING,
    327               name))));
    328 
    329 }
    330 
    331 void PluginInstallerInfoBarDelegate::Replace(
    332     InfoBarDelegate* infobar,
    333     PluginInstaller* installer,
    334     scoped_ptr<PluginMetadata> plugin_metadata,
    335     bool new_install,
    336     const string16& message) {
    337   DCHECK(infobar->owner());
    338   infobar->owner()->ReplaceInfoBar(infobar, scoped_ptr<InfoBarDelegate>(
    339       new PluginInstallerInfoBarDelegate(
    340           infobar->owner(), installer, plugin_metadata.Pass(),
    341           PluginInstallerInfoBarDelegate::InstallCallback(), new_install,
    342           message)));
    343 }
    344 
    345 PluginInstallerInfoBarDelegate::PluginInstallerInfoBarDelegate(
    346     InfoBarService* infobar_service,
    347     PluginInstaller* installer,
    348     scoped_ptr<PluginMetadata> plugin_metadata,
    349     const InstallCallback& callback,
    350     bool new_install,
    351     const string16& message)
    352     : ConfirmInfoBarDelegate(infobar_service),
    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 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 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 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 = google_util::AppendGoogleLocaleParam(GURL(
    397         "https://www.google.com/support/chrome/bin/answer.py?answer=142064"));
    398   }
    399   web_contents()->OpenURL(content::OpenURLParams(
    400       url, content::Referrer(),
    401       (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
    402       content::PAGE_TRANSITION_LINK, false));
    403   return false;
    404 }
    405 
    406 void PluginInstallerInfoBarDelegate::DownloadStarted() {
    407   ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING,
    408                                                 plugin_metadata_->name()));
    409 }
    410 
    411 void PluginInstallerInfoBarDelegate::DownloadCancelled() {
    412   ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED,
    413                                                 plugin_metadata_->name()));
    414 }
    415 
    416 void PluginInstallerInfoBarDelegate::DownloadError(const std::string& message) {
    417   ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT,
    418                                                 plugin_metadata_->name()));
    419 }
    420 
    421 void PluginInstallerInfoBarDelegate::DownloadFinished() {
    422   ReplaceWithInfoBar(
    423       l10n_util::GetStringFUTF16(
    424           new_install_ ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING,
    425           plugin_metadata_->name()));
    426 }
    427 
    428 void PluginInstallerInfoBarDelegate::OnlyWeakObserversLeft() {
    429   if (owner())
    430     owner()->RemoveInfoBar(this);
    431 }
    432 
    433 void PluginInstallerInfoBarDelegate::ReplaceWithInfoBar(
    434     const 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) || !owner())
    439     return;
    440   Replace(this, installer(), plugin_metadata_->Clone(), new_install_, message);
    441 }
    442 
    443 
    444 #if defined(OS_WIN)
    445 
    446 // PluginMetroModeInfoBarDelegate ---------------------------------------------
    447 
    448 // static
    449 void PluginMetroModeInfoBarDelegate::Create(
    450     InfoBarService* infobar_service,
    451     PluginMetroModeInfoBarDelegate::Mode mode,
    452     const string16& name) {
    453   infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
    454       new PluginMetroModeInfoBarDelegate(infobar_service, mode, name)));
    455 }
    456 
    457 PluginMetroModeInfoBarDelegate::PluginMetroModeInfoBarDelegate(
    458     InfoBarService* infobar_service,
    459     PluginMetroModeInfoBarDelegate::Mode mode,
    460     const string16& name)
    461     : ConfirmInfoBarDelegate(infobar_service),
    462       mode_(mode),
    463       name_(name) {
    464 }
    465 
    466 PluginMetroModeInfoBarDelegate::~PluginMetroModeInfoBarDelegate() {
    467 }
    468 
    469 int PluginMetroModeInfoBarDelegate::GetIconID() const {
    470   return IDR_INFOBAR_PLUGIN_INSTALL;
    471 }
    472 
    473 string16 PluginMetroModeInfoBarDelegate::GetMessageText() const {
    474   return l10n_util::GetStringFUTF16((mode_ == MISSING_PLUGIN) ?
    475       IDS_METRO_MISSING_PLUGIN_PROMPT : IDS_METRO_NPAPI_PLUGIN_PROMPT, name_);
    476 }
    477 
    478 int PluginMetroModeInfoBarDelegate::GetButtons() const {
    479   return (mode_ == MISSING_PLUGIN) ? BUTTON_OK : (BUTTON_OK | BUTTON_CANCEL);
    480 }
    481 
    482 string16 PluginMetroModeInfoBarDelegate::GetButtonLabel(
    483     InfoBarButton button) const {
    484   if (button == BUTTON_CANCEL)
    485     return l10n_util::GetStringUTF16(IDS_DONT_ASK_AGAIN_INFOBAR_BUTTON_LABEL);
    486   return l10n_util::GetStringUTF16((mode_ == MISSING_PLUGIN) ?
    487       IDS_WIN8_DESKTOP_RESTART : IDS_WIN8_RESTART);
    488 }
    489 
    490 void LaunchDesktopInstanceHelper(const string16& url) {
    491   base::FilePath exe_path;
    492   if (!PathService::Get(base::FILE_EXE, &exe_path))
    493     return;
    494   base::FilePath shortcut_path(
    495       ShellIntegration::GetStartMenuShortcut(exe_path));
    496 
    497   SHELLEXECUTEINFO sei = { sizeof(sei) };
    498   sei.fMask = SEE_MASK_FLAG_LOG_USAGE;
    499   sei.nShow = SW_SHOWNORMAL;
    500   sei.lpFile = shortcut_path.value().c_str();
    501   sei.lpDirectory = L"";
    502   sei.lpParameters = url.c_str();
    503   ShellExecuteEx(&sei);
    504 }
    505 
    506 bool PluginMetroModeInfoBarDelegate::Accept() {
    507 #if defined(USE_AURA) && defined(USE_ASH)
    508   // We need to PostTask as there is some IO involved.
    509   content::BrowserThread::PostTask(
    510       content::BrowserThread::PROCESS_LAUNCHER, FROM_HERE,
    511       base::Bind(&LaunchDesktopInstanceHelper,
    512                  UTF8ToUTF16(web_contents()->GetURL().spec())));
    513 #else
    514   chrome::AttemptRestartWithModeSwitch();
    515 #endif
    516   return true;
    517 }
    518 
    519 bool PluginMetroModeInfoBarDelegate::Cancel() {
    520   DCHECK_EQ(DESKTOP_MODE_REQUIRED, mode_);
    521   Profile::FromBrowserContext(web_contents()->GetBrowserContext())->
    522       GetHostContentSettingsMap()->SetContentSetting(
    523           ContentSettingsPattern::FromURL(web_contents()->GetURL()),
    524           ContentSettingsPattern::Wildcard(),
    525           CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP, std::string(),
    526           CONTENT_SETTING_BLOCK);
    527   return true;
    528 }
    529 
    530 string16 PluginMetroModeInfoBarDelegate::GetLinkText() const {
    531   return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
    532 }
    533 
    534 bool PluginMetroModeInfoBarDelegate::LinkClicked(
    535     WindowOpenDisposition disposition) {
    536   web_contents()->OpenURL(content::OpenURLParams(
    537       GURL((mode_ == MISSING_PLUGIN) ?
    538           "https://support.google.com/chrome/?p=ib_display_in_desktop" :
    539           "https://support.google.com/chrome/?p=ib_redirect_to_desktop"),
    540       content::Referrer(),
    541       (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
    542       content::PAGE_TRANSITION_LINK, false));
    543   return false;
    544 }
    545 
    546 #endif  // defined(OS_WIN)
    547 
    548 #endif  // defined(ENABLE_PLUGIN_INSTALLATION)
    549