blob: 763e622e908cd03faf9435c89b70fc6ecee629b2 [file] [log] [blame] [edit]
// Copyright (c) 2012 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/plugins/plugin_observer.h"
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/api/infobars/confirm_infobar_delegate.h"
#include "chrome/browser/api/infobars/simple_alert_infobar_delegate.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/infobars/infobar_tab_helper.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/plugins/plugin_finder.h"
#include "chrome/browser/plugins/plugin_infobar_delegates.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.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/webplugininfo.h"
#if defined(ENABLE_PLUGIN_INSTALLATION)
#include "chrome/browser/plugins/plugin_installer.h"
#include "chrome/browser/plugins/plugin_installer_observer.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
#endif // defined(ENABLE_PLUGIN_INSTALLATION)
#if defined(OS_WIN)
#include "base/win/metro.h"
#endif
using content::OpenURLParams;
using content::PluginService;
using content::Referrer;
using content::WebContents;
int PluginObserver::kUserDataKey;
namespace {
#if defined(ENABLE_PLUGIN_INSTALLATION)
// ConfirmInstallDialogDelegate ------------------------------------------------
class ConfirmInstallDialogDelegate : public TabModalConfirmDialogDelegate,
public WeakPluginInstallerObserver {
public:
ConfirmInstallDialogDelegate(content::WebContents* web_contents,
PluginInstaller* installer);
// TabModalConfirmDialogDelegate methods:
virtual string16 GetTitle() OVERRIDE;
virtual string16 GetMessage() OVERRIDE;
virtual string16 GetAcceptButtonTitle() OVERRIDE;
virtual void OnAccepted() OVERRIDE;
virtual void OnCanceled() OVERRIDE;
// WeakPluginInstallerObserver methods:
virtual void DownloadStarted() OVERRIDE;
virtual void OnlyWeakObserversLeft() OVERRIDE;
private:
content::WebContents* web_contents_;
};
ConfirmInstallDialogDelegate::ConfirmInstallDialogDelegate(
content::WebContents* web_contents,
PluginInstaller* installer)
: TabModalConfirmDialogDelegate(web_contents),
WeakPluginInstallerObserver(installer),
web_contents_(web_contents) {
}
string16 ConfirmInstallDialogDelegate::GetTitle() {
return l10n_util::GetStringFUTF16(
IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_TITLE, installer()->name());
}
string16 ConfirmInstallDialogDelegate::GetMessage() {
return l10n_util::GetStringFUTF16(IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_MSG,
installer()->name());
}
string16 ConfirmInstallDialogDelegate::GetAcceptButtonTitle() {
return l10n_util::GetStringUTF16(
IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_ACCEPT_BUTTON);
}
void ConfirmInstallDialogDelegate::OnAccepted() {
installer()->StartInstalling(TabContents::FromWebContents(web_contents_));
}
void ConfirmInstallDialogDelegate::OnCanceled() {
}
void ConfirmInstallDialogDelegate::DownloadStarted() {
Cancel();
}
void ConfirmInstallDialogDelegate::OnlyWeakObserversLeft() {
Cancel();
}
#endif // defined(ENABLE_PLUGIN_INSTALLATION)
} // namespace
// PluginObserver -------------------------------------------------------------
#if defined(ENABLE_PLUGIN_INSTALLATION)
class PluginObserver::PluginPlaceholderHost : public PluginInstallerObserver {
public:
PluginPlaceholderHost(PluginObserver* observer,
int routing_id,
PluginInstaller* installer)
: PluginInstallerObserver(installer),
observer_(observer),
routing_id_(routing_id) {
DCHECK(installer);
switch (installer->state()) {
case PluginInstaller::INSTALLER_STATE_IDLE: {
observer->Send(new ChromeViewMsg_FoundMissingPlugin(routing_id_,
installer->name()));
break;
}
case PluginInstaller::INSTALLER_STATE_DOWNLOADING: {
DownloadStarted();
break;
}
}
}
// PluginInstallerObserver methods:
virtual void DownloadStarted() OVERRIDE {
observer_->Send(new ChromeViewMsg_StartedDownloadingPlugin(routing_id_));
}
virtual void DownloadError(const std::string& msg) OVERRIDE {
observer_->Send(new ChromeViewMsg_ErrorDownloadingPlugin(routing_id_, msg));
}
virtual void DownloadCancelled() OVERRIDE {
observer_->Send(new ChromeViewMsg_CancelledDownloadingPlugin(routing_id_));
}
virtual void DownloadFinished() OVERRIDE {
observer_->Send(new ChromeViewMsg_FinishedDownloadingPlugin(routing_id_));
}
private:
// Weak pointer; owns us.
PluginObserver* observer_;
int routing_id_;
};
#endif // defined(ENABLE_PLUGIN_INSTALLATION)
PluginObserver::PluginObserver(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
}
PluginObserver::~PluginObserver() {
#if defined(ENABLE_PLUGIN_INSTALLATION)
STLDeleteValues(&plugin_placeholders_);
#endif
}
void PluginObserver::PluginCrashed(const FilePath& plugin_path) {
DCHECK(!plugin_path.value().empty());
string16 plugin_name =
PluginService::GetInstance()->GetPluginDisplayNameByPath(plugin_path);
gfx::Image* icon = &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
IDR_INFOBAR_PLUGIN_CRASHED);
TabContents* tab_contents = TabContents::FromWebContents(web_contents());
InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
infobar_helper->AddInfoBar(
new SimpleAlertInfoBarDelegate(
infobar_helper,
icon,
l10n_util::GetStringFUTF16(IDS_PLUGIN_CRASHED_PROMPT, plugin_name),
true));
}
bool PluginObserver::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(PluginObserver, message)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_BlockedOutdatedPlugin,
OnBlockedOutdatedPlugin)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_BlockedUnauthorizedPlugin,
OnBlockedUnauthorizedPlugin)
#if defined(ENABLE_PLUGIN_INSTALLATION)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FindMissingPlugin,
OnFindMissingPlugin)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RemovePluginPlaceholderHost,
OnRemovePluginPlaceholderHost)
#endif
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_OpenAboutPlugins,
OnOpenAboutPlugins)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CouldNotLoadPlugin,
OnCouldNotLoadPlugin)
IPC_MESSAGE_UNHANDLED(return false)
IPC_END_MESSAGE_MAP()
return true;
}
void PluginObserver::OnBlockedUnauthorizedPlugin(
const string16& name,
const std::string& identifier) {
TabContents* tab_contents = TabContents::FromWebContents(web_contents());
InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
infobar_helper->AddInfoBar(
new UnauthorizedPluginInfoBarDelegate(
infobar_helper,
tab_contents->profile()->GetHostContentSettingsMap(),
name, identifier));
}
void PluginObserver::OnBlockedOutdatedPlugin(int placeholder_id,
const std::string& identifier) {
#if defined(ENABLE_PLUGIN_INSTALLATION)
// Find plugin to update.
PluginInstaller* installer =
PluginFinder::GetInstance()->FindPluginWithIdentifier(identifier);
DCHECK(installer) << "Couldn't find PluginInstaller for identifier "
<< identifier;
plugin_placeholders_[placeholder_id] =
new PluginPlaceholderHost(this, placeholder_id, installer);
TabContents* tab_contents = TabContents::FromWebContents(web_contents());
InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
infobar_helper->AddInfoBar(
OutdatedPluginInfoBarDelegate::Create(web_contents(), installer));
#else
// If we don't support third-party plug-in installation, we shouldn't have
// outdated plug-ins.
NOTREACHED();
#endif // defined(ENABLE_PLUGIN_INSTALLATION)
}
#if defined(ENABLE_PLUGIN_INSTALLATION)
void PluginObserver::OnFindMissingPlugin(int placeholder_id,
const std::string& mime_type) {
std::string lang = "en-US"; // Oh yes.
PluginInstaller* installer =
PluginFinder::GetInstance()->FindPlugin(mime_type, lang);
if (!installer) {
Send(new ChromeViewMsg_DidNotFindMissingPlugin(placeholder_id));
return;
}
plugin_placeholders_[placeholder_id] =
new PluginPlaceholderHost(this, placeholder_id, installer);
TabContents* tab_contents = TabContents::FromWebContents(web_contents());
InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
InfoBarDelegate* delegate;
#if !defined(OS_WIN)
delegate = PluginInstallerInfoBarDelegate::Create(
infobar_helper, installer,
base::Bind(&PluginObserver::InstallMissingPlugin,
weak_ptr_factory_.GetWeakPtr(), installer));
#else
delegate = base::win::IsMetroProcess() ?
PluginMetroModeInfoBarDelegate::Create(
infobar_helper, installer->name()) :
PluginInstallerInfoBarDelegate::Create(
infobar_helper, installer,
base::Bind(&PluginObserver::InstallMissingPlugin,
weak_ptr_factory_.GetWeakPtr(), installer));
#endif
infobar_helper->AddInfoBar(delegate);
}
void PluginObserver::InstallMissingPlugin(PluginInstaller* installer) {
if (installer->url_for_display()) {
installer->OpenDownloadURL(web_contents());
} else {
TabModalConfirmDialog::Create(
new ConfirmInstallDialogDelegate(web_contents(), installer),
TabContents::FromWebContents(web_contents()));
}
}
void PluginObserver::OnRemovePluginPlaceholderHost(int placeholder_id) {
std::map<int, PluginPlaceholderHost*>::iterator it =
plugin_placeholders_.find(placeholder_id);
if (it == plugin_placeholders_.end()) {
NOTREACHED();
return;
}
delete it->second;
plugin_placeholders_.erase(it);
}
#endif // defined(ENABLE_PLUGIN_INSTALLATION)
void PluginObserver::OnOpenAboutPlugins() {
web_contents()->OpenURL(OpenURLParams(
GURL(chrome::kAboutPluginsURL),
content::Referrer(web_contents()->GetURL(),
WebKit::WebReferrerPolicyDefault),
NEW_FOREGROUND_TAB, content::PAGE_TRANSITION_AUTO_BOOKMARK, false));
}
void PluginObserver::OnCouldNotLoadPlugin(const FilePath& plugin_path) {
g_browser_process->metrics_service()->LogPluginLoadingError(plugin_path);
string16 plugin_name =
PluginService::GetInstance()->GetPluginDisplayNameByPath(plugin_path);
TabContents* tab_contents = TabContents::FromWebContents(web_contents());
InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
infobar_helper->AddInfoBar(new SimpleAlertInfoBarDelegate(
infobar_helper,
&ResourceBundle::GetSharedInstance().GetNativeImageNamed(
IDR_INFOBAR_PLUGIN_CRASHED),
l10n_util::GetStringFUTF16(IDS_PLUGIN_INITIALIZATION_ERROR_PROMPT,
plugin_name),
true /* auto_expire */));
}