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.
5 #include "chrome/browser/ui/pdf/pdf_unsupported_feature.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/lifetime/application_lifetime.h"
11 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
12 #include "chrome/browser/plugins/plugin_metadata.h"
13 #include "chrome/browser/plugins/plugin_prefs.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/renderer_preferences_util.h"
16 #include "chrome/browser/tab_contents/tab_util.h"
17 #include "chrome/browser/ui/pdf/open_pdf_in_reader_prompt_delegate.h"
18 #include "chrome/browser/ui/pdf/pdf_tab_helper.h"
19 #include "chrome/common/chrome_content_client.h"
20 #include "content/public/browser/interstitial_page.h"
21 #include "content/public/browser/interstitial_page_delegate.h"
22 #include "content/public/browser/navigation_details.h"
23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/browser/page_navigator.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_process_host.h"
27 #include "content/public/browser/render_view_host.h"
28 #include "content/public/browser/user_metrics.h"
29 #include "content/public/browser/web_contents.h"
30 #include "grit/browser_resources.h"
31 #include "grit/generated_resources.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/base/resource/resource_bundle.h"
34 #include "ui/base/webui/jstemplate_builder.h"
37 #include "base/win/metro.h"
38 #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
41 using base::UserMetricsAction
;
42 using content::InterstitialPage
;
43 using content::OpenURLParams
;
44 using content::Referrer
;
45 using content::WebContents
;
46 using content::WebPluginInfo
;
51 const char kAdobeReaderUpdateUrl
[] = "http://www.adobe.com/go/getreader_chrome";
53 // The prompt delegate used to ask the user if they want to use Adobe Reader
55 class PDFEnableAdobeReaderPromptDelegate
56 : public OpenPDFInReaderPromptDelegate
{
58 explicit PDFEnableAdobeReaderPromptDelegate(Profile
* profile
);
59 virtual ~PDFEnableAdobeReaderPromptDelegate();
61 // OpenPDFInReaderPromptDelegate
62 virtual base::string16
GetMessageText() const OVERRIDE
;
63 virtual base::string16
GetAcceptButtonText() const OVERRIDE
;
64 virtual base::string16
GetCancelButtonText() const OVERRIDE
;
65 virtual bool ShouldExpire(
66 const content::LoadCommittedDetails
& details
) const OVERRIDE
;
67 virtual void Accept() OVERRIDE
;
68 virtual void Cancel() OVERRIDE
;
76 DISALLOW_IMPLICIT_CONSTRUCTORS(PDFEnableAdobeReaderPromptDelegate
);
79 PDFEnableAdobeReaderPromptDelegate::PDFEnableAdobeReaderPromptDelegate(
82 content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarShown"));
85 PDFEnableAdobeReaderPromptDelegate::~PDFEnableAdobeReaderPromptDelegate() {
88 bool PDFEnableAdobeReaderPromptDelegate::ShouldExpire(
89 const content::LoadCommittedDetails
& details
) const {
90 content::PageTransition transition
=
91 content::PageTransitionStripQualifier(details
.entry
->GetTransitionType());
92 // We don't want to expire on a reload, because that is how we open the PDF in
94 return !details
.is_in_page
&& transition
!= content::PAGE_TRANSITION_RELOAD
;
97 void PDFEnableAdobeReaderPromptDelegate::Accept() {
98 content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarOK"));
99 PluginPrefs
* plugin_prefs
= PluginPrefs::GetForProfile(profile_
).get();
100 plugin_prefs
->EnablePluginGroup(
101 true, base::ASCIIToUTF16(PluginMetadata::kAdobeReaderGroupName
));
102 plugin_prefs
->EnablePluginGroup(
103 false, base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName
));
106 void PDFEnableAdobeReaderPromptDelegate::Cancel() {
107 content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarCancel"));
110 base::string16
PDFEnableAdobeReaderPromptDelegate::GetAcceptButtonText() const {
111 return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_ALWAYS_USE_READER_BUTTON
);
114 base::string16
PDFEnableAdobeReaderPromptDelegate::GetCancelButtonText() const {
115 return l10n_util::GetStringUTF16(IDS_DONE
);
118 base::string16
PDFEnableAdobeReaderPromptDelegate::GetMessageText() const {
119 return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_QUESTION_ALWAYS_USE_READER
);
122 // Launch the url to get the latest Adbobe Reader installer.
123 void OpenReaderUpdateURL(WebContents
* web_contents
) {
124 OpenURLParams
params(
125 GURL(kAdobeReaderUpdateUrl
), Referrer(), NEW_FOREGROUND_TAB
,
126 content::PAGE_TRANSITION_LINK
, false);
127 web_contents
->OpenURL(params
);
130 // Opens the PDF using Adobe Reader.
131 void OpenUsingReader(WebContents
* web_contents
,
132 const WebPluginInfo
& reader_plugin
,
133 OpenPDFInReaderPromptDelegate
* delegate
) {
134 ChromePluginServiceFilter::GetInstance()->OverridePluginForFrame(
135 web_contents
->GetRenderProcessHost()->GetID(),
136 web_contents
->GetMainFrame()->GetRoutingID(),
137 web_contents
->GetURL(),
139 web_contents
->ReloadFocusedFrame(false);
141 PDFTabHelper
* pdf_tab_helper
= PDFTabHelper::FromWebContents(web_contents
);
143 pdf_tab_helper
->ShowOpenInReaderPrompt(make_scoped_ptr(delegate
));
146 // An interstitial to be used when the user chooses to open a PDF using Adobe
147 // Reader, but it is out of date.
148 class PDFUnsupportedFeatureInterstitial
149 : public content::InterstitialPageDelegate
{
151 PDFUnsupportedFeatureInterstitial(
152 WebContents
* web_contents
,
153 const WebPluginInfo
& reader_webplugininfo
)
154 : web_contents_(web_contents
),
155 reader_webplugininfo_(reader_webplugininfo
) {
156 content::RecordAction(UserMetricsAction("PDF_ReaderInterstitialShown"));
157 interstitial_page_
= InterstitialPage::Create(
158 web_contents
, false, web_contents
->GetURL(), this);
159 interstitial_page_
->Show();
163 // InterstitialPageDelegate implementation.
164 virtual std::string
GetHTMLContents() OVERRIDE
{
165 base::DictionaryValue strings
;
168 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_TITLE
));
171 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_BODY
));
174 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_UPDATE
));
177 l10n_util::GetStringUTF16(
178 IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_PROCEED
));
181 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_OK
));
184 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_CANCEL
));
186 base::StringPiece
html(ResourceBundle::GetSharedInstance().
187 GetRawDataResource(IDR_READER_OUT_OF_DATE_HTML
));
189 return webui::GetI18nTemplateHtml(html
, &strings
);
192 virtual void CommandReceived(const std::string
& command
) OVERRIDE
{
193 if (command
== "0") {
194 content::RecordAction(
195 UserMetricsAction("PDF_ReaderInterstitialCancel"));
196 interstitial_page_
->DontProceed();
200 if (command
== "1") {
201 content::RecordAction(
202 UserMetricsAction("PDF_ReaderInterstitialUpdate"));
203 OpenReaderUpdateURL(web_contents_
);
204 } else if (command
== "2") {
205 content::RecordAction(
206 UserMetricsAction("PDF_ReaderInterstitialIgnore"));
207 // Pretend that the plug-in is up-to-date so that we don't block it.
208 reader_webplugininfo_
.version
= base::ASCIIToUTF16("11.0.0.0");
209 OpenUsingReader(web_contents_
, reader_webplugininfo_
, NULL
);
213 interstitial_page_
->Proceed();
216 virtual void OverrideRendererPrefs(
217 content::RendererPreferences
* prefs
) OVERRIDE
{
219 Profile::FromBrowserContext(web_contents_
->GetBrowserContext());
220 renderer_preferences_util::UpdateFromSystemSettings(prefs
, profile
);
224 WebContents
* web_contents_
;
225 WebPluginInfo reader_webplugininfo_
;
226 InterstitialPage
* interstitial_page_
; // Owns us.
228 DISALLOW_COPY_AND_ASSIGN(PDFUnsupportedFeatureInterstitial
);
231 // The delegate for the bubble used to inform the user that we don't support a
232 // feature in the PDF.
233 class PDFUnsupportedFeaturePromptDelegate
234 : public OpenPDFInReaderPromptDelegate
{
236 PDFUnsupportedFeaturePromptDelegate(
237 WebContents
* web_contents
,
238 const AdobeReaderPluginInfo
& reader_info
);
239 virtual ~PDFUnsupportedFeaturePromptDelegate();
241 // OpenPDFInReaderPromptDelegate:
242 virtual base::string16
GetMessageText() const OVERRIDE
;
243 virtual base::string16
GetAcceptButtonText() const OVERRIDE
;
244 virtual base::string16
GetCancelButtonText() const OVERRIDE
;
245 virtual bool ShouldExpire(
246 const content::LoadCommittedDetails
& details
) const OVERRIDE
;
247 virtual void Accept() OVERRIDE
;
248 virtual void Cancel() OVERRIDE
;
251 WebContents
* web_contents_
;
252 const AdobeReaderPluginInfo reader_info_
;
254 DISALLOW_IMPLICIT_CONSTRUCTORS(PDFUnsupportedFeaturePromptDelegate
);
257 PDFUnsupportedFeaturePromptDelegate::PDFUnsupportedFeaturePromptDelegate(
258 WebContents
* web_contents
,
259 const AdobeReaderPluginInfo
& reader_info
)
260 : web_contents_(web_contents
),
261 reader_info_(reader_info
) {
262 content::RecordAction(reader_info_
.is_installed
?
263 UserMetricsAction("PDF_UseReaderInfoBarShown") :
264 UserMetricsAction("PDF_InstallReaderInfoBarShown"));
267 PDFUnsupportedFeaturePromptDelegate::~PDFUnsupportedFeaturePromptDelegate() {
270 base::string16
PDFUnsupportedFeaturePromptDelegate::GetMessageText() const {
271 return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_MESSAGE
);
274 base::string16
PDFUnsupportedFeaturePromptDelegate::GetAcceptButtonText()
276 if (base::win::IsMetroProcess())
277 return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_METRO_MODE_LINK
);
279 return l10n_util::GetStringUTF16(
280 reader_info_
.is_installed
? IDS_PDF_BUBBLE_OPEN_IN_READER_LINK
281 : IDS_PDF_BUBBLE_INSTALL_READER_LINK
);
284 base::string16
PDFUnsupportedFeaturePromptDelegate::GetCancelButtonText()
286 return l10n_util::GetStringUTF16(IDS_DONE
);
289 bool PDFUnsupportedFeaturePromptDelegate::ShouldExpire(
290 const content::LoadCommittedDetails
& details
) const {
291 return !details
.is_in_page
;
294 void PDFUnsupportedFeaturePromptDelegate::Accept() {
295 if (base::win::IsMetroProcess()) {
296 chrome::AttemptRestartWithModeSwitch();
300 if (!reader_info_
.is_installed
) {
301 content::RecordAction(UserMetricsAction("PDF_InstallReaderInfoBarOK"));
302 OpenReaderUpdateURL(web_contents_
);
306 content::RecordAction(UserMetricsAction("PDF_UseReaderInfoBarOK"));
308 if (!reader_info_
.is_secure
) {
309 new PDFUnsupportedFeatureInterstitial(web_contents_
,
310 reader_info_
.plugin_info
);
315 Profile::FromBrowserContext(web_contents_
->GetBrowserContext());
316 OpenPDFInReaderPromptDelegate
* delegate
=
317 new PDFEnableAdobeReaderPromptDelegate(profile
);
319 OpenUsingReader(web_contents_
, reader_info_
.plugin_info
, delegate
);
322 void PDFUnsupportedFeaturePromptDelegate::Cancel() {
323 content::RecordAction(reader_info_
.is_installed
?
324 UserMetricsAction("PDF_UseReaderInfoBarCancel") :
325 UserMetricsAction("PDF_InstallReaderInfoBarCancel"));
328 void MaybeShowOpenPDFInReaderPrompt(WebContents
* web_contents
,
329 const AdobeReaderPluginInfo
& reader_info
) {
330 // If the Reader plugin is disabled by policy, don't prompt them.
331 if (!reader_info
.is_installed
|| !reader_info
.is_enabled
)
334 scoped_ptr
<OpenPDFInReaderPromptDelegate
> prompt(
335 new PDFUnsupportedFeaturePromptDelegate(web_contents
, reader_info
));
336 PDFTabHelper
* pdf_tab_helper
= PDFTabHelper::FromWebContents(web_contents
);
337 pdf_tab_helper
->ShowOpenInReaderPrompt(prompt
.Pass());
340 void GotPluginsCallback(int process_id
,
342 const AdobeReaderPluginInfo
& reader_info
) {
343 WebContents
* web_contents
=
344 tab_util::GetWebContentsByID(process_id
, routing_id
);
346 MaybeShowOpenPDFInReaderPrompt(web_contents
, reader_info
);
350 #endif // defined(OS_WIN)
352 void PDFHasUnsupportedFeature(WebContents
* web_contents
) {
354 // Only works for Windows for now. For Mac, we'll have to launch the file
355 // externally since Adobe Reader doesn't work inside Chrome.
357 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
358 AdobeReaderPluginInfo reader_info
;
359 if (GetAdobeReaderPluginInfo(profile
, &reader_info
)) {
360 MaybeShowOpenPDFInReaderPrompt(web_contents
, reader_info
);
363 GetAdobeReaderPluginInfoAsync(
365 base::Bind(&GotPluginsCallback
,
366 web_contents
->GetRenderProcessHost()->GetID(),
367 web_contents
->GetRenderViewHost()->GetRoutingID()));
368 #endif // defined(OS_WIN)