blob: 52a428e0f5466f0e4a357af2831d6ab0e095da8e [file] [log] [blame]
// 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/ui/pdf/pdf_unsupported_feature.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
#include "chrome/browser/plugins/plugin_metadata.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/grit/browser_resources.h"
#include "chrome/grit/generated_resources.h"
#include "components/pdf/browser/open_pdf_in_reader_prompt_client.h"
#include "components/pdf/browser/pdf_web_contents_helper.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/renderer_preferences.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/jstemplate_builder.h"
#if defined(OS_WIN)
#include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
#endif
using base::UserMetricsAction;
using content::InterstitialPage;
using content::OpenURLParams;
using content::Referrer;
using content::WebContents;
using content::WebPluginInfo;
#if defined(OS_WIN)
namespace {
const char kAdobeReaderUpdateUrl[] = "http://www.adobe.com/go/getreader_chrome";
// The prompt delegate used to ask the user if they want to use Adobe Reader
// by default.
class PDFEnableAdobeReaderPromptClient
: public pdf::OpenPDFInReaderPromptClient {
public:
explicit PDFEnableAdobeReaderPromptClient(Profile* profile);
~PDFEnableAdobeReaderPromptClient() override;
// pdf::OpenPDFInReaderPromptClient
base::string16 GetMessageText() const override;
base::string16 GetAcceptButtonText() const override;
base::string16 GetCancelButtonText() const override;
bool ShouldExpire(
const content::LoadCommittedDetails& details) const override;
void Accept() override;
void Cancel() override;
private:
void OnYes();
void OnNo();
Profile* profile_;
DISALLOW_IMPLICIT_CONSTRUCTORS(PDFEnableAdobeReaderPromptClient);
};
PDFEnableAdobeReaderPromptClient::PDFEnableAdobeReaderPromptClient(
Profile* profile)
: profile_(profile) {
content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarShown"));
}
PDFEnableAdobeReaderPromptClient::~PDFEnableAdobeReaderPromptClient() {
}
bool PDFEnableAdobeReaderPromptClient::ShouldExpire(
const content::LoadCommittedDetails& details) const {
ui::PageTransition transition =
ui::PageTransitionStripQualifier(details.entry->GetTransitionType());
// We don't want to expire on a reload, because that is how we open the PDF in
// Reader.
return !details.is_in_page &&
!ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD);
}
void PDFEnableAdobeReaderPromptClient::Accept() {
content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarOK"));
PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get();
plugin_prefs->EnablePluginGroup(
true, base::ASCIIToUTF16(PluginMetadata::kAdobeReaderGroupName));
plugin_prefs->EnablePluginGroup(
false, base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName));
}
void PDFEnableAdobeReaderPromptClient::Cancel() {
content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarCancel"));
}
base::string16 PDFEnableAdobeReaderPromptClient::GetAcceptButtonText() const {
return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_ALWAYS_USE_READER_BUTTON);
}
base::string16 PDFEnableAdobeReaderPromptClient::GetCancelButtonText() const {
return l10n_util::GetStringUTF16(IDS_DONE);
}
base::string16 PDFEnableAdobeReaderPromptClient::GetMessageText() const {
return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_QUESTION_ALWAYS_USE_READER);
}
// Launch the url to get the latest Adbobe Reader installer.
void OpenReaderUpdateURL(WebContents* web_contents) {
OpenURLParams params(GURL(kAdobeReaderUpdateUrl), Referrer(),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_LINK, false);
web_contents->OpenURL(params);
}
// Opens the PDF using Adobe Reader.
void OpenUsingReader(WebContents* web_contents,
const WebPluginInfo& reader_plugin,
pdf::OpenPDFInReaderPromptClient* client) {
ChromePluginServiceFilter::GetInstance()->OverridePluginForFrame(
web_contents->GetRenderProcessHost()->GetID(),
web_contents->GetMainFrame()->GetRoutingID(),
web_contents->GetURL(),
reader_plugin);
web_contents->ReloadFocusedFrame(false);
pdf::PDFWebContentsHelper* pdf_tab_helper =
pdf::PDFWebContentsHelper::FromWebContents(web_contents);
if (client)
pdf_tab_helper->ShowOpenInReaderPrompt(base::WrapUnique(client));
}
// An interstitial to be used when the user chooses to open a PDF using Adobe
// Reader, but it is out of date.
class PDFUnsupportedFeatureInterstitial
: public content::InterstitialPageDelegate {
public:
PDFUnsupportedFeatureInterstitial(
WebContents* web_contents,
const WebPluginInfo& reader_webplugininfo)
: web_contents_(web_contents),
reader_webplugininfo_(reader_webplugininfo) {
content::RecordAction(UserMetricsAction("PDF_ReaderInterstitialShown"));
interstitial_page_ = InterstitialPage::Create(
web_contents, false, web_contents->GetURL(), this);
interstitial_page_->Show();
}
protected:
// InterstitialPageDelegate implementation.
std::string GetHTMLContents() override {
base::DictionaryValue strings;
strings.SetString(
"title",
l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_TITLE));
strings.SetString(
"headLine",
l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_BODY));
strings.SetString(
"update",
l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_UPDATE));
strings.SetString(
"open_with_reader",
l10n_util::GetStringUTF16(
IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_PROCEED));
strings.SetString(
"ok",
l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_OK));
strings.SetString(
"cancel",
l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_CANCEL));
base::StringPiece html(ResourceBundle::GetSharedInstance().
GetRawDataResource(IDR_READER_OUT_OF_DATE_HTML));
return webui::GetI18nTemplateHtml(html, &strings);
}
void CommandReceived(const std::string& command) override {
if (command == "0") {
content::RecordAction(
UserMetricsAction("PDF_ReaderInterstitialCancel"));
interstitial_page_->DontProceed();
return;
}
if (command == "1") {
content::RecordAction(
UserMetricsAction("PDF_ReaderInterstitialUpdate"));
OpenReaderUpdateURL(web_contents_);
} else if (command == "2") {
content::RecordAction(
UserMetricsAction("PDF_ReaderInterstitialIgnore"));
// Pretend that the plugin is up to date so that we don't block it.
reader_webplugininfo_.version = base::ASCIIToUTF16("11.0.0.0");
OpenUsingReader(web_contents_, reader_webplugininfo_, NULL);
} else {
NOTREACHED();
}
interstitial_page_->Proceed();
}
void OverrideRendererPrefs(content::RendererPreferences* prefs) override {
Profile* profile =
Profile::FromBrowserContext(web_contents_->GetBrowserContext());
renderer_preferences_util::UpdateFromSystemSettings(
prefs, profile, web_contents_);
}
private:
WebContents* web_contents_;
WebPluginInfo reader_webplugininfo_;
InterstitialPage* interstitial_page_; // Owns us.
DISALLOW_COPY_AND_ASSIGN(PDFUnsupportedFeatureInterstitial);
};
// The delegate for the bubble used to inform the user that we don't support a
// feature in the PDF.
class PDFUnsupportedFeaturePromptClient
: public pdf::OpenPDFInReaderPromptClient {
public:
PDFUnsupportedFeaturePromptClient(WebContents* web_contents,
const AdobeReaderPluginInfo& reader_info);
~PDFUnsupportedFeaturePromptClient() override;
// pdf::OpenPDFInReaderPromptClient:
base::string16 GetMessageText() const override;
base::string16 GetAcceptButtonText() const override;
base::string16 GetCancelButtonText() const override;
bool ShouldExpire(
const content::LoadCommittedDetails& details) const override;
void Accept() override;
void Cancel() override;
private:
WebContents* web_contents_;
const AdobeReaderPluginInfo reader_info_;
DISALLOW_IMPLICIT_CONSTRUCTORS(PDFUnsupportedFeaturePromptClient);
};
PDFUnsupportedFeaturePromptClient::PDFUnsupportedFeaturePromptClient(
WebContents* web_contents,
const AdobeReaderPluginInfo& reader_info)
: web_contents_(web_contents), reader_info_(reader_info) {
content::RecordAction(reader_info_.is_installed ?
UserMetricsAction("PDF_UseReaderInfoBarShown") :
UserMetricsAction("PDF_InstallReaderInfoBarShown"));
}
PDFUnsupportedFeaturePromptClient::~PDFUnsupportedFeaturePromptClient() {
}
base::string16 PDFUnsupportedFeaturePromptClient::GetMessageText() const {
return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_MESSAGE);
}
base::string16 PDFUnsupportedFeaturePromptClient::GetAcceptButtonText() const {
return l10n_util::GetStringUTF16(
reader_info_.is_installed ? IDS_PDF_BUBBLE_OPEN_IN_READER_LINK
: IDS_PDF_BUBBLE_INSTALL_READER_LINK);
}
base::string16 PDFUnsupportedFeaturePromptClient::GetCancelButtonText() const {
return l10n_util::GetStringUTF16(IDS_DONE);
}
bool PDFUnsupportedFeaturePromptClient::ShouldExpire(
const content::LoadCommittedDetails& details) const {
return !details.is_in_page;
}
void PDFUnsupportedFeaturePromptClient::Accept() {
if (!reader_info_.is_installed) {
content::RecordAction(UserMetricsAction("PDF_InstallReaderInfoBarOK"));
OpenReaderUpdateURL(web_contents_);
return;
}
content::RecordAction(UserMetricsAction("PDF_UseReaderInfoBarOK"));
if (!reader_info_.is_secure) {
new PDFUnsupportedFeatureInterstitial(web_contents_,
reader_info_.plugin_info);
return;
}
Profile* profile =
Profile::FromBrowserContext(web_contents_->GetBrowserContext());
pdf::OpenPDFInReaderPromptClient* client =
new PDFEnableAdobeReaderPromptClient(profile);
OpenUsingReader(web_contents_, reader_info_.plugin_info, client);
}
void PDFUnsupportedFeaturePromptClient::Cancel() {
content::RecordAction(reader_info_.is_installed ?
UserMetricsAction("PDF_UseReaderInfoBarCancel") :
UserMetricsAction("PDF_InstallReaderInfoBarCancel"));
}
void MaybeShowOpenPDFInReaderPrompt(WebContents* web_contents,
const AdobeReaderPluginInfo& reader_info) {
// If the Reader plugin is disabled by policy, don't prompt them.
if (!reader_info.is_installed || !reader_info.is_enabled)
return;
std::unique_ptr<pdf::OpenPDFInReaderPromptClient> prompt(
new PDFUnsupportedFeaturePromptClient(web_contents, reader_info));
pdf::PDFWebContentsHelper* pdf_tab_helper =
pdf::PDFWebContentsHelper::FromWebContents(web_contents);
pdf_tab_helper->ShowOpenInReaderPrompt(std::move(prompt));
}
void GotPluginsCallback(int process_id,
int routing_id,
const AdobeReaderPluginInfo& reader_info) {
WebContents* web_contents =
tab_util::GetWebContentsByID(process_id, routing_id);
if (web_contents)
MaybeShowOpenPDFInReaderPrompt(web_contents, reader_info);
}
} // namespace
#endif // defined(OS_WIN)
void PDFHasUnsupportedFeature(WebContents* web_contents) {
#if defined(OS_WIN)
// Only works for Windows for now. For Mac, we'll have to launch the file
// externally since Adobe Reader doesn't work inside Chrome.
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
AdobeReaderPluginInfo reader_info;
if (GetAdobeReaderPluginInfo(profile, &reader_info)) {
MaybeShowOpenPDFInReaderPrompt(web_contents, reader_info);
return;
}
GetAdobeReaderPluginInfoAsync(
profile,
base::Bind(&GotPluginsCallback,
web_contents->GetRenderProcessHost()->GetID(),
web_contents->GetRenderViewHost()->GetRoutingID()));
#endif // defined(OS_WIN)
}