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/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