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
47using base::UserMetricsAction;
48
49
50// PluginInfoBarDelegate ------------------------------------------------------
51
52PluginInfoBarDelegate::PluginInfoBarDelegate(const std::string& identifier)
53    : ConfirmInfoBarDelegate(),
54      identifier_(identifier) {
55}
56
57PluginInfoBarDelegate::~PluginInfoBarDelegate() {
58}
59
60bool 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
69void PluginInfoBarDelegate::LoadBlockedPlugins() {
70  content::WebContents* web_contents =
71      InfoBarService::WebContentsFromInfoBar(infobar());
72  ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
73      web_contents, true, identifier_);
74}
75
76int PluginInfoBarDelegate::GetIconID() const {
77  return IDR_INFOBAR_PLUGIN_INSTALL;
78}
79
80base::string16 PluginInfoBarDelegate::GetLinkText() const {
81  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
82}
83
84
85// UnauthorizedPluginInfoBarDelegate ------------------------------------------
86
87// static
88void 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
116UnauthorizedPluginInfoBarDelegate::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
125UnauthorizedPluginInfoBarDelegate::~UnauthorizedPluginInfoBarDelegate() {
126  content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Closed"));
127}
128
129std::string UnauthorizedPluginInfoBarDelegate::GetLearnMoreURL() const {
130  return chrome::kBlockedPluginLearnMoreURL;
131}
132
133base::string16 UnauthorizedPluginInfoBarDelegate::GetMessageText() const {
134  return l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, name_);
135}
136
137base::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
143bool UnauthorizedPluginInfoBarDelegate::Accept() {
144  content::RecordAction(
145      UserMetricsAction("BlockedPluginInfobar.AllowThisTime"));
146  LoadBlockedPlugins();
147  return true;
148}
149
150bool 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
159void UnauthorizedPluginInfoBarDelegate::InfoBarDismissed() {
160  content::RecordAction(UserMetricsAction("BlockedPluginInfobar.Dismissed"));
161}
162
163bool 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
174void 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
189OutdatedPluginInfoBarDelegate::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
220OutdatedPluginInfoBarDelegate::~OutdatedPluginInfoBarDelegate() {
221  content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Closed"));
222}
223
224std::string OutdatedPluginInfoBarDelegate::GetLearnMoreURL() const {
225  return chrome::kOutdatedPluginLearnMoreURL;
226}
227
228base::string16 OutdatedPluginInfoBarDelegate::GetMessageText() const {
229  return message_;
230}
231
232base::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
238bool 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
254bool OutdatedPluginInfoBarDelegate::Cancel() {
255  content::RecordAction(
256      UserMetricsAction("OutdatedPluginInfobar.AllowThisTime"));
257  LoadBlockedPlugins();
258  return true;
259}
260
261void OutdatedPluginInfoBarDelegate::InfoBarDismissed() {
262  content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Dismissed"));
263}
264
265bool OutdatedPluginInfoBarDelegate::LinkClicked(
266    WindowOpenDisposition disposition) {
267  content::RecordAction(UserMetricsAction("OutdatedPluginInfobar.LearnMore"));
268  return PluginInfoBarDelegate::LinkClicked(disposition);
269}
270
271void OutdatedPluginInfoBarDelegate::DownloadStarted() {
272  ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING,
273                                                plugin_metadata_->name()));
274}
275
276void OutdatedPluginInfoBarDelegate::DownloadError(const std::string& message) {
277  ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT,
278                                                plugin_metadata_->name()));
279}
280
281void OutdatedPluginInfoBarDelegate::DownloadCancelled() {
282  ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED,
283                                                plugin_metadata_->name()));
284}
285
286void OutdatedPluginInfoBarDelegate::DownloadFinished() {
287  ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_UPDATING,
288                                                plugin_metadata_->name()));
289}
290
291void OutdatedPluginInfoBarDelegate::OnlyWeakObserversLeft() {
292  infobar()->RemoveSelf();
293}
294
295void 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
309void 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
332void 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
347PluginInstallerInfoBarDelegate::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
361PluginInstallerInfoBarDelegate::~PluginInstallerInfoBarDelegate() {
362}
363
364int PluginInstallerInfoBarDelegate::GetIconID() const {
365  return IDR_INFOBAR_PLUGIN_INSTALL;
366}
367
368base::string16 PluginInstallerInfoBarDelegate::GetMessageText() const {
369  return message_;
370}
371
372int PluginInstallerInfoBarDelegate::GetButtons() const {
373  return callback_.is_null() ? BUTTON_NONE : BUTTON_OK;
374}
375
376base::string16 PluginInstallerInfoBarDelegate::GetButtonLabel(
377    InfoBarButton button) const {
378  DCHECK_EQ(BUTTON_OK, button);
379  return l10n_util::GetStringUTF16(IDS_PLUGININSTALLER_INSTALLPLUGIN_BUTTON);
380}
381
382bool PluginInstallerInfoBarDelegate::Accept() {
383  callback_.Run(plugin_metadata_.get());
384  return false;
385}
386
387base::string16 PluginInstallerInfoBarDelegate::GetLinkText() const {
388  return l10n_util::GetStringUTF16(new_install_ ?
389      IDS_PLUGININSTALLER_PROBLEMSINSTALLING :
390      IDS_PLUGININSTALLER_PROBLEMSUPDATING);
391}
392
393bool 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
408void PluginInstallerInfoBarDelegate::DownloadStarted() {
409  ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOADING,
410                                                plugin_metadata_->name()));
411}
412
413void PluginInstallerInfoBarDelegate::DownloadCancelled() {
414  ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_CANCELLED,
415                                                plugin_metadata_->name()));
416}
417
418void PluginInstallerInfoBarDelegate::DownloadError(const std::string& message) {
419  ReplaceWithInfoBar(l10n_util::GetStringFUTF16(IDS_PLUGIN_DOWNLOAD_ERROR_SHORT,
420                                                plugin_metadata_->name()));
421}
422
423void PluginInstallerInfoBarDelegate::DownloadFinished() {
424  ReplaceWithInfoBar(
425      l10n_util::GetStringFUTF16(
426          new_install_ ? IDS_PLUGIN_INSTALLING : IDS_PLUGIN_UPDATING,
427          plugin_metadata_->name()));
428}
429
430void PluginInstallerInfoBarDelegate::OnlyWeakObserversLeft() {
431  infobar()->RemoveSelf();
432}
433
434void 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
451void 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
460PluginMetroModeInfoBarDelegate::PluginMetroModeInfoBarDelegate(
461    PluginMetroModeInfoBarDelegate::Mode mode,
462    const base::string16& name)
463    : ConfirmInfoBarDelegate(),
464      mode_(mode),
465      name_(name) {
466}
467
468PluginMetroModeInfoBarDelegate::~PluginMetroModeInfoBarDelegate() {
469}
470
471int PluginMetroModeInfoBarDelegate::GetIconID() const {
472  return IDR_INFOBAR_PLUGIN_INSTALL;
473}
474
475base::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
480int PluginMetroModeInfoBarDelegate::GetButtons() const {
481  return BUTTON_OK;
482}
483
484base::string16 PluginMetroModeInfoBarDelegate::GetButtonLabel(
485    InfoBarButton button) const {
486  return l10n_util::GetStringUTF16(IDS_WIN_DESKTOP_RESTART);
487}
488
489void 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
503bool PluginMetroModeInfoBarDelegate::Accept() {
504  chrome::AttemptRestartToDesktopMode();
505  return true;
506}
507
508base::string16 PluginMetroModeInfoBarDelegate::GetLinkText() const {
509  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
510}
511
512bool 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