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/common/chrome_content_client.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "components/pdf/browser/open_pdf_in_reader_prompt_client.h"
20 #include "components/pdf/browser/pdf_web_contents_helper.h"
21 #include "content/public/browser/interstitial_page.h"
22 #include "content/public/browser/interstitial_page_delegate.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/page_navigator.h"
26 #include "content/public/browser/render_frame_host.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/user_metrics.h"
30 #include "content/public/browser/web_contents.h"
31 #include "grit/browser_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 PDFEnableAdobeReaderPromptClient
56 : public pdf::OpenPDFInReaderPromptClient
{
58 explicit PDFEnableAdobeReaderPromptClient(Profile
* profile
);
59 virtual ~PDFEnableAdobeReaderPromptClient();
61 // pdf::OpenPDFInReaderPromptClient
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(PDFEnableAdobeReaderPromptClient
);
79 PDFEnableAdobeReaderPromptClient::PDFEnableAdobeReaderPromptClient(
82 content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarShown"));
85 PDFEnableAdobeReaderPromptClient::~PDFEnableAdobeReaderPromptClient() {
88 bool PDFEnableAdobeReaderPromptClient::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 PDFEnableAdobeReaderPromptClient::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 PDFEnableAdobeReaderPromptClient::Cancel() {
107 content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarCancel"));
110 base::string16
PDFEnableAdobeReaderPromptClient::GetAcceptButtonText() const {
111 return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_ALWAYS_USE_READER_BUTTON
);
114 base::string16
PDFEnableAdobeReaderPromptClient::GetCancelButtonText() const {
115 return l10n_util::GetStringUTF16(IDS_DONE
);
118 base::string16
PDFEnableAdobeReaderPromptClient::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 pdf::OpenPDFInReaderPromptClient
* client
) {
134 ChromePluginServiceFilter::GetInstance()->OverridePluginForFrame(
135 web_contents
->GetRenderProcessHost()->GetID(),
136 web_contents
->GetMainFrame()->GetRoutingID(),
137 web_contents
->GetURL(),
139 web_contents
->ReloadFocusedFrame(false);
141 pdf::PDFWebContentsHelper
* pdf_tab_helper
=
142 pdf::PDFWebContentsHelper::FromWebContents(web_contents
);
144 pdf_tab_helper
->ShowOpenInReaderPrompt(make_scoped_ptr(client
));
147 // An interstitial to be used when the user chooses to open a PDF using Adobe
148 // Reader, but it is out of date.
149 class PDFUnsupportedFeatureInterstitial
150 : public content::InterstitialPageDelegate
{
152 PDFUnsupportedFeatureInterstitial(
153 WebContents
* web_contents
,
154 const WebPluginInfo
& reader_webplugininfo
)
155 : web_contents_(web_contents
),
156 reader_webplugininfo_(reader_webplugininfo
) {
157 content::RecordAction(UserMetricsAction("PDF_ReaderInterstitialShown"));
158 interstitial_page_
= InterstitialPage::Create(
159 web_contents
, false, web_contents
->GetURL(), this);
160 interstitial_page_
->Show();
164 // InterstitialPageDelegate implementation.
165 virtual std::string
GetHTMLContents() OVERRIDE
{
166 base::DictionaryValue strings
;
169 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_TITLE
));
172 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_BODY
));
175 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_UPDATE
));
178 l10n_util::GetStringUTF16(
179 IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_PROCEED
));
182 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_OK
));
185 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_CANCEL
));
187 base::StringPiece
html(ResourceBundle::GetSharedInstance().
188 GetRawDataResource(IDR_READER_OUT_OF_DATE_HTML
));
190 return webui::GetI18nTemplateHtml(html
, &strings
);
193 virtual void CommandReceived(const std::string
& command
) OVERRIDE
{
194 if (command
== "0") {
195 content::RecordAction(
196 UserMetricsAction("PDF_ReaderInterstitialCancel"));
197 interstitial_page_
->DontProceed();
201 if (command
== "1") {
202 content::RecordAction(
203 UserMetricsAction("PDF_ReaderInterstitialUpdate"));
204 OpenReaderUpdateURL(web_contents_
);
205 } else if (command
== "2") {
206 content::RecordAction(
207 UserMetricsAction("PDF_ReaderInterstitialIgnore"));
208 // Pretend that the plug-in is up-to-date so that we don't block it.
209 reader_webplugininfo_
.version
= base::ASCIIToUTF16("11.0.0.0");
210 OpenUsingReader(web_contents_
, reader_webplugininfo_
, NULL
);
214 interstitial_page_
->Proceed();
217 virtual void OverrideRendererPrefs(
218 content::RendererPreferences
* prefs
) OVERRIDE
{
220 Profile::FromBrowserContext(web_contents_
->GetBrowserContext());
221 renderer_preferences_util::UpdateFromSystemSettings(prefs
, profile
);
225 WebContents
* web_contents_
;
226 WebPluginInfo reader_webplugininfo_
;
227 InterstitialPage
* interstitial_page_
; // Owns us.
229 DISALLOW_COPY_AND_ASSIGN(PDFUnsupportedFeatureInterstitial
);
232 // The delegate for the bubble used to inform the user that we don't support a
233 // feature in the PDF.
234 class PDFUnsupportedFeaturePromptClient
235 : public pdf::OpenPDFInReaderPromptClient
{
237 PDFUnsupportedFeaturePromptClient(WebContents
* web_contents
,
238 const AdobeReaderPluginInfo
& reader_info
);
239 virtual ~PDFUnsupportedFeaturePromptClient();
241 // pdf::OpenPDFInReaderPromptClient:
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(PDFUnsupportedFeaturePromptClient
);
257 PDFUnsupportedFeaturePromptClient::PDFUnsupportedFeaturePromptClient(
258 WebContents
* web_contents
,
259 const AdobeReaderPluginInfo
& reader_info
)
260 : web_contents_(web_contents
), reader_info_(reader_info
) {
261 content::RecordAction(reader_info_
.is_installed
?
262 UserMetricsAction("PDF_UseReaderInfoBarShown") :
263 UserMetricsAction("PDF_InstallReaderInfoBarShown"));
266 PDFUnsupportedFeaturePromptClient::~PDFUnsupportedFeaturePromptClient() {
269 base::string16
PDFUnsupportedFeaturePromptClient::GetMessageText() const {
270 return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_MESSAGE
);
273 base::string16
PDFUnsupportedFeaturePromptClient::GetAcceptButtonText() const {
274 if (base::win::IsMetroProcess())
275 return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_METRO_MODE_LINK
);
277 return l10n_util::GetStringUTF16(
278 reader_info_
.is_installed
? IDS_PDF_BUBBLE_OPEN_IN_READER_LINK
279 : IDS_PDF_BUBBLE_INSTALL_READER_LINK
);
282 base::string16
PDFUnsupportedFeaturePromptClient::GetCancelButtonText() const {
283 return l10n_util::GetStringUTF16(IDS_DONE
);
286 bool PDFUnsupportedFeaturePromptClient::ShouldExpire(
287 const content::LoadCommittedDetails
& details
) const {
288 return !details
.is_in_page
;
291 void PDFUnsupportedFeaturePromptClient::Accept() {
292 if (base::win::IsMetroProcess()) {
293 chrome::AttemptRestartWithModeSwitch();
297 if (!reader_info_
.is_installed
) {
298 content::RecordAction(UserMetricsAction("PDF_InstallReaderInfoBarOK"));
299 OpenReaderUpdateURL(web_contents_
);
303 content::RecordAction(UserMetricsAction("PDF_UseReaderInfoBarOK"));
305 if (!reader_info_
.is_secure
) {
306 new PDFUnsupportedFeatureInterstitial(web_contents_
,
307 reader_info_
.plugin_info
);
312 Profile::FromBrowserContext(web_contents_
->GetBrowserContext());
313 pdf::OpenPDFInReaderPromptClient
* client
=
314 new PDFEnableAdobeReaderPromptClient(profile
);
316 OpenUsingReader(web_contents_
, reader_info_
.plugin_info
, client
);
319 void PDFUnsupportedFeaturePromptClient::Cancel() {
320 content::RecordAction(reader_info_
.is_installed
?
321 UserMetricsAction("PDF_UseReaderInfoBarCancel") :
322 UserMetricsAction("PDF_InstallReaderInfoBarCancel"));
325 void MaybeShowOpenPDFInReaderPrompt(WebContents
* web_contents
,
326 const AdobeReaderPluginInfo
& reader_info
) {
327 // If the Reader plugin is disabled by policy, don't prompt them.
328 if (!reader_info
.is_installed
|| !reader_info
.is_enabled
)
331 scoped_ptr
<pdf::OpenPDFInReaderPromptClient
> prompt(
332 new PDFUnsupportedFeaturePromptClient(web_contents
, reader_info
));
333 pdf::PDFWebContentsHelper
* pdf_tab_helper
=
334 pdf::PDFWebContentsHelper::FromWebContents(web_contents
);
335 pdf_tab_helper
->ShowOpenInReaderPrompt(prompt
.Pass());
338 void GotPluginsCallback(int process_id
,
340 const AdobeReaderPluginInfo
& reader_info
) {
341 WebContents
* web_contents
=
342 tab_util::GetWebContentsByID(process_id
, routing_id
);
344 MaybeShowOpenPDFInReaderPrompt(web_contents
, reader_info
);
348 #endif // defined(OS_WIN)
350 void PDFHasUnsupportedFeature(WebContents
* web_contents
) {
352 // Only works for Windows for now. For Mac, we'll have to launch the file
353 // externally since Adobe Reader doesn't work inside Chrome.
355 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
356 AdobeReaderPluginInfo reader_info
;
357 if (GetAdobeReaderPluginInfo(profile
, &reader_info
)) {
358 MaybeShowOpenPDFInReaderPrompt(web_contents
, reader_info
);
361 GetAdobeReaderPluginInfoAsync(
363 base::Bind(&GotPluginsCallback
,
364 web_contents
->GetRenderProcessHost()->GetID(),
365 web_contents
->GetRenderViewHost()->GetRoutingID()));
366 #endif // defined(OS_WIN)