// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/plugin_observer.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/plugin_installer_infobar_delegate.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
#include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/view_messages.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/plugins/npapi/default_plugin_shared.h"
#include "webkit/plugins/npapi/plugin_group.h"
#include "webkit/plugins/npapi/plugin_list.h"
#include "webkit/plugins/npapi/webplugininfo.h"
namespace {
// PluginInfoBarDelegate ------------------------------------------------------
class PluginInfoBarDelegate : public ConfirmInfoBarDelegate {
public:
PluginInfoBarDelegate(TabContents* tab_contents, const string16& name);
protected:
virtual ~PluginInfoBarDelegate();
// ConfirmInfoBarDelegate:
virtual void InfoBarClosed();
virtual bool Cancel();
virtual bool LinkClicked(WindowOpenDisposition disposition);
virtual std::string GetLearnMoreURL() const = 0;
string16 name_;
TabContents* tab_contents_;
private:
// ConfirmInfoBarDelegate:
virtual SkBitmap* GetIcon() const;
virtual string16 GetLinkText();
DISALLOW_COPY_AND_ASSIGN(PluginInfoBarDelegate);
};
PluginInfoBarDelegate::PluginInfoBarDelegate(TabContents* tab_contents,
const string16& name)
: ConfirmInfoBarDelegate(tab_contents),
name_(name),
tab_contents_(tab_contents) {
}
PluginInfoBarDelegate::~PluginInfoBarDelegate() {
}
void PluginInfoBarDelegate::InfoBarClosed() {
delete this;
}
bool PluginInfoBarDelegate::Cancel() {
tab_contents_->render_view_host()->LoadBlockedPlugins();
return true;
}
bool PluginInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
GURL url = google_util::AppendGoogleLocaleParam(GURL(GetLearnMoreURL()));
tab_contents_->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
return false;
}
SkBitmap* PluginInfoBarDelegate::GetIcon() const {
return ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_INFOBAR_PLUGIN_INSTALL);
}
string16 PluginInfoBarDelegate::GetLinkText() {
return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
}
// BlockedPluginInfoBarDelegate -----------------------------------------------
class BlockedPluginInfoBarDelegate : public PluginInfoBarDelegate {
public:
BlockedPluginInfoBarDelegate(TabContents* tab_contents,
const string16& name);
private:
virtual ~BlockedPluginInfoBarDelegate();
// PluginInfoBarDelegate:
virtual string16 GetMessageText() const;
virtual string16 GetButtonLabel(InfoBarButton button) const;
virtual bool Accept();
virtual bool Cancel();
virtual void InfoBarClosed();
virtual void InfoBarDismissed();
virtual bool LinkClicked(WindowOpenDisposition disposition);
virtual std::string GetLearnMoreURL() const;
DISALLOW_COPY_AND_ASSIGN(BlockedPluginInfoBarDelegate);
};
BlockedPluginInfoBarDelegate::BlockedPluginInfoBarDelegate(
TabContents* tab_contents,
const string16& utf16_name)
: PluginInfoBarDelegate(tab_contents, utf16_name) {
UserMetrics::RecordAction(UserMetricsAction("BlockedPluginInfobar.Shown"));
std::string name = UTF16ToUTF8(utf16_name);
if (name == webkit::npapi::PluginGroup::kJavaGroupName)
UserMetrics::RecordAction(
UserMetricsAction("BlockedPluginInfobar.Shown.Java"));
else if (name == webkit::npapi::PluginGroup::kQuickTimeGroupName)
UserMetrics::RecordAction(
UserMetricsAction("BlockedPluginInfobar.Shown.QuickTime"));
else if (name == webkit::npapi::PluginGroup::kShockwaveGroupName)
UserMetrics::RecordAction(
UserMetricsAction("BlockedPluginInfobar.Shown.Shockwave"));
else if (name == webkit::npapi::PluginGroup::kRealPlayerGroupName)
UserMetrics::RecordAction(
UserMetricsAction("BlockedPluginInfobar.Shown.RealPlayer"));
}
BlockedPluginInfoBarDelegate::~BlockedPluginInfoBarDelegate() {
}
std::string BlockedPluginInfoBarDelegate::GetLearnMoreURL() const {
return chrome::kBlockedPluginLearnMoreURL;
}
string16 BlockedPluginInfoBarDelegate::GetMessageText() const {
return l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, name_);
}
string16 BlockedPluginInfoBarDelegate::GetButtonLabel(
InfoBarButton button) const {
return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
IDS_PLUGIN_ENABLE_TEMPORARILY : IDS_PLUGIN_ENABLE_ALWAYS);
}
bool BlockedPluginInfoBarDelegate::Accept() {
UserMetrics::RecordAction(
UserMetricsAction("BlockedPluginInfobar.AllowThisTime"));
return PluginInfoBarDelegate::Cancel();
}
bool BlockedPluginInfoBarDelegate::Cancel() {
UserMetrics::RecordAction(
UserMetricsAction("BlockedPluginInfobar.AlwaysAllow"));
tab_contents_->profile()->GetHostContentSettingsMap()->AddExceptionForURL(
tab_contents_->GetURL(), CONTENT_SETTINGS_TYPE_PLUGINS, std::string(),
CONTENT_SETTING_ALLOW);
return PluginInfoBarDelegate::Cancel();
}
void BlockedPluginInfoBarDelegate::InfoBarDismissed() {
UserMetrics::RecordAction(
UserMetricsAction("BlockedPluginInfobar.Dismissed"));
}
void BlockedPluginInfoBarDelegate::InfoBarClosed() {
UserMetrics::RecordAction(UserMetricsAction("BlockedPluginInfobar.Closed"));
PluginInfoBarDelegate::InfoBarClosed();
}
bool BlockedPluginInfoBarDelegate::LinkClicked(
WindowOpenDisposition disposition) {
UserMetrics::RecordAction(
UserMetricsAction("BlockedPluginInfobar.LearnMore"));
return PluginInfoBarDelegate::LinkClicked(disposition);
}
// OutdatedPluginInfoBarDelegate ----------------------------------------------
class OutdatedPluginInfoBarDelegate : public PluginInfoBarDelegate {
public:
OutdatedPluginInfoBarDelegate(TabContents* tab_contents,
const string16& name,
const GURL& update_url);
private:
virtual ~OutdatedPluginInfoBarDelegate();
// PluginInfoBarDelegate:
virtual string16 GetMessageText() const;
virtual string16 GetButtonLabel(InfoBarButton button) const;
virtual bool Accept();
virtual bool Cancel();
virtual void InfoBarClosed();
virtual void InfoBarDismissed();
virtual bool LinkClicked(WindowOpenDisposition disposition);
virtual std::string GetLearnMoreURL() const;
GURL update_url_;
DISALLOW_COPY_AND_ASSIGN(OutdatedPluginInfoBarDelegate);
};
OutdatedPluginInfoBarDelegate::OutdatedPluginInfoBarDelegate(
TabContents* tab_contents,
const string16& utf16_name,
const GURL& update_url)
: PluginInfoBarDelegate(tab_contents, utf16_name),
update_url_(update_url) {
UserMetrics::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Shown"));
std::string name = UTF16ToUTF8(utf16_name);
if (name == webkit::npapi::PluginGroup::kJavaGroupName)
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.Shown.Java"));
else if (name == webkit::npapi::PluginGroup::kQuickTimeGroupName)
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.Shown.QuickTime"));
else if (name == webkit::npapi::PluginGroup::kShockwaveGroupName)
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.Shown.Shockwave"));
else if (name == webkit::npapi::PluginGroup::kRealPlayerGroupName)
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.Shown.RealPlayer"));
else if (name == webkit::npapi::PluginGroup::kSilverlightGroupName)
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.Shown.Silverlight"));
else if (name == webkit::npapi::PluginGroup::kAdobeReaderGroupName)
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.Shown.Reader"));
}
OutdatedPluginInfoBarDelegate::~OutdatedPluginInfoBarDelegate() {
}
std::string OutdatedPluginInfoBarDelegate::GetLearnMoreURL() const {
return chrome::kOutdatedPluginLearnMoreURL;
}
string16 OutdatedPluginInfoBarDelegate::GetMessageText() const {
return l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED_PROMPT, name_);
}
string16 OutdatedPluginInfoBarDelegate::GetButtonLabel(
InfoBarButton button) const {
return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
IDS_PLUGIN_UPDATE : IDS_PLUGIN_ENABLE_TEMPORARILY);
}
bool OutdatedPluginInfoBarDelegate::Accept() {
UserMetrics::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Update"));
tab_contents_->OpenURL(update_url_, GURL(), NEW_FOREGROUND_TAB,
PageTransition::LINK);
return false;
}
bool OutdatedPluginInfoBarDelegate::Cancel() {
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.AllowThisTime"));
return PluginInfoBarDelegate::Cancel();
}
void OutdatedPluginInfoBarDelegate::InfoBarDismissed() {
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.Dismissed"));
}
void OutdatedPluginInfoBarDelegate::InfoBarClosed() {
UserMetrics::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Closed"));
PluginInfoBarDelegate::InfoBarClosed();
}
bool OutdatedPluginInfoBarDelegate::LinkClicked(
WindowOpenDisposition disposition) {
UserMetrics::RecordAction(
UserMetricsAction("OutdatedPluginInfobar.LearnMore"));
return PluginInfoBarDelegate::LinkClicked(disposition);
}
} // namespace
// PluginObserver -------------------------------------------------------------
PluginObserver::PluginObserver(TabContents* tab_contents)
: TabContentsObserver(tab_contents) {
}
PluginObserver::~PluginObserver() {
}
bool PluginObserver::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(PluginObserver, message)
IPC_MESSAGE_HANDLER(ViewHostMsg_MissingPluginStatus, OnMissingPluginStatus)
IPC_MESSAGE_HANDLER(ViewHostMsg_CrashedPlugin, OnCrashedPlugin)
IPC_MESSAGE_HANDLER(ViewHostMsg_BlockedOutdatedPlugin,
OnBlockedOutdatedPlugin)
IPC_MESSAGE_UNHANDLED(return false)
IPC_END_MESSAGE_MAP()
return true;
}
PluginInstallerInfoBarDelegate* PluginObserver::GetPluginInstaller() {
if (plugin_installer_ == NULL)
plugin_installer_.reset(new PluginInstallerInfoBarDelegate(tab_contents()));
return plugin_installer_->AsPluginInstallerInfoBarDelegate();
}
void PluginObserver::OnMissingPluginStatus(int status) {
// TODO(PORT): pull in when plug-ins work
#if defined(OS_WIN)
if (status == webkit::npapi::default_plugin::MISSING_PLUGIN_AVAILABLE) {
tab_contents()->AddInfoBar(
new PluginInstallerInfoBarDelegate(tab_contents()));
return;
}
DCHECK_EQ(webkit::npapi::default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD,
status);
for (size_t i = 0; i < tab_contents()->infobar_count(); ++i) {
InfoBarDelegate* delegate = tab_contents()->GetInfoBarDelegateAt(i);
if (delegate->AsPluginInstallerInfoBarDelegate() != NULL) {
tab_contents()->RemoveInfoBar(delegate);
return;
}
}
#endif
}
void PluginObserver::OnCrashedPlugin(const FilePath& plugin_path) {
DCHECK(!plugin_path.value().empty());
string16 plugin_name = plugin_path.LossyDisplayName();
webkit::npapi::WebPluginInfo plugin_info;
if (webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
plugin_path, &plugin_info) &&
!plugin_info.name.empty()) {
plugin_name = plugin_info.name;
#if defined(OS_MACOSX)
// Many plugins on the Mac have .plugin in the actual name, which looks
// terrible, so look for that and strip it off if present.
const std::string kPluginExtension = ".plugin";
if (EndsWith(plugin_name, ASCIIToUTF16(kPluginExtension), true))
plugin_name.erase(plugin_name.length() - kPluginExtension.length());
#endif // OS_MACOSX
}
SkBitmap* crash_icon = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_INFOBAR_PLUGIN_CRASHED);
tab_contents()->AddInfoBar(new SimpleAlertInfoBarDelegate(tab_contents(),
crash_icon,
l10n_util::GetStringFUTF16(IDS_PLUGIN_CRASHED_PROMPT, plugin_name),
true));
}
void PluginObserver::OnBlockedOutdatedPlugin(const string16& name,
const GURL& update_url) {
tab_contents()->AddInfoBar(update_url.is_empty() ?
static_cast<InfoBarDelegate*>(new BlockedPluginInfoBarDelegate(
tab_contents(), name)) :
new OutdatedPluginInfoBarDelegate(tab_contents(), name, update_url));
}