[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / ui / pdf / pdf_unsupported_feature.cc
blob6252408c76dd0e87c3a756e2ef1e31346f6364de
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"
7 #include "base/bind.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "base/version.h"
13 #include "chrome/browser/lifetime/application_lifetime.h"
14 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
15 #include "chrome/browser/plugins/plugin_finder.h"
16 #include "chrome/browser/plugins/plugin_metadata.h"
17 #include "chrome/browser/plugins/plugin_prefs.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/renderer_preferences_util.h"
20 #include "chrome/browser/tab_contents/tab_util.h"
21 #include "chrome/browser/ui/pdf/open_pdf_in_reader_prompt_delegate.h"
22 #include "chrome/browser/ui/pdf/pdf_tab_helper.h"
23 #include "chrome/common/chrome_content_client.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/interstitial_page.h"
26 #include "content/public/browser/interstitial_page_delegate.h"
27 #include "content/public/browser/navigation_details.h"
28 #include "content/public/browser/navigation_entry.h"
29 #include "content/public/browser/plugin_service.h"
30 #include "content/public/browser/render_frame_host.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "content/public/browser/render_view_host.h"
33 #include "content/public/browser/user_metrics.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/common/page_transition_types.h"
36 #include "grit/browser_resources.h"
37 #include "grit/generated_resources.h"
38 #include "grit/theme_resources.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/resource/resource_bundle.h"
41 #include "ui/base/webui/jstemplate_builder.h"
42 #include "ui/gfx/image/image.h"
44 #if defined(OS_WIN)
45 #include "base/win/metro.h"
46 #endif
48 using base::UserMetricsAction;
49 using content::InterstitialPage;
50 using content::OpenURLParams;
51 using content::PluginService;
52 using content::Referrer;
53 using content::WebContents;
54 using content::WebPluginInfo;
56 namespace {
58 const char kAdobeReaderUpdateUrl[] = "http://www.adobe.com/go/getreader_chrome";
60 #if defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
61 const char kAdobeReaderIdentifier[] = "adobe-reader";
62 #endif
64 // The prompt delegate used to ask the user if they want to use Adobe Reader
65 // by default.
66 class PDFEnableAdobeReaderPromptDelegate
67 : public OpenPDFInReaderPromptDelegate {
68 public:
69 explicit PDFEnableAdobeReaderPromptDelegate(Profile* profile);
70 virtual ~PDFEnableAdobeReaderPromptDelegate();
72 // OpenPDFInReaderPromptDelegate
73 virtual base::string16 GetMessageText() const OVERRIDE;
74 virtual base::string16 GetAcceptButtonText() const OVERRIDE;
75 virtual base::string16 GetCancelButtonText() const OVERRIDE;
76 virtual bool ShouldExpire(
77 const content::LoadCommittedDetails& details) const OVERRIDE;
78 virtual void Accept() OVERRIDE;
79 virtual void Cancel() OVERRIDE;
81 private:
82 void OnYes();
83 void OnNo();
85 Profile* profile_;
87 DISALLOW_IMPLICIT_CONSTRUCTORS(PDFEnableAdobeReaderPromptDelegate);
90 PDFEnableAdobeReaderPromptDelegate::PDFEnableAdobeReaderPromptDelegate(
91 Profile* profile)
92 : profile_(profile) {
93 content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarShown"));
96 PDFEnableAdobeReaderPromptDelegate::~PDFEnableAdobeReaderPromptDelegate() {
99 bool PDFEnableAdobeReaderPromptDelegate::ShouldExpire(
100 const content::LoadCommittedDetails& details) const {
101 content::PageTransition transition =
102 content::PageTransitionStripQualifier(details.entry->GetTransitionType());
103 // We don't want to expire on a reload, because that is how we open the PDF in
104 // Reader.
105 return !details.is_in_page && transition != content::PAGE_TRANSITION_RELOAD;
108 void PDFEnableAdobeReaderPromptDelegate::Accept() {
109 content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarOK"));
110 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get();
111 plugin_prefs->EnablePluginGroup(
112 true, base::ASCIIToUTF16(PluginMetadata::kAdobeReaderGroupName));
113 plugin_prefs->EnablePluginGroup(
114 false, base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName));
117 void PDFEnableAdobeReaderPromptDelegate::Cancel() {
118 content::RecordAction(UserMetricsAction("PDF_EnableReaderInfoBarCancel"));
121 base::string16 PDFEnableAdobeReaderPromptDelegate::GetAcceptButtonText() const {
122 return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_ALWAYS_USE_READER_BUTTON);
125 base::string16 PDFEnableAdobeReaderPromptDelegate::GetCancelButtonText() const {
126 return l10n_util::GetStringUTF16(IDS_DONE);
129 base::string16 PDFEnableAdobeReaderPromptDelegate::GetMessageText() const {
130 return l10n_util::GetStringUTF16(IDS_PDF_INFOBAR_QUESTION_ALWAYS_USE_READER);
133 // Launch the url to get the latest Adbobe Reader installer.
134 void OpenReaderUpdateURL(WebContents* web_contents) {
135 OpenURLParams params(
136 GURL(kAdobeReaderUpdateUrl), Referrer(), NEW_FOREGROUND_TAB,
137 content::PAGE_TRANSITION_LINK, false);
138 web_contents->OpenURL(params);
141 // Opens the PDF using Adobe Reader.
142 void OpenUsingReader(WebContents* web_contents,
143 const WebPluginInfo& reader_plugin,
144 OpenPDFInReaderPromptDelegate* delegate) {
145 ChromePluginServiceFilter::GetInstance()->OverridePluginForFrame(
146 web_contents->GetRenderProcessHost()->GetID(),
147 web_contents->GetMainFrame()->GetRoutingID(),
148 web_contents->GetURL(),
149 reader_plugin);
150 web_contents->ReloadFocusedFrame(false);
152 PDFTabHelper* pdf_tab_helper = PDFTabHelper::FromWebContents(web_contents);
153 if (delegate)
154 pdf_tab_helper->ShowOpenInReaderPrompt(make_scoped_ptr(delegate));
157 // An interstitial to be used when the user chooses to open a PDF using Adobe
158 // Reader, but it is out of date.
159 class PDFUnsupportedFeatureInterstitial
160 : public content::InterstitialPageDelegate {
161 public:
162 PDFUnsupportedFeatureInterstitial(
163 WebContents* web_contents,
164 const WebPluginInfo& reader_webplugininfo)
165 : web_contents_(web_contents),
166 reader_webplugininfo_(reader_webplugininfo) {
167 content::RecordAction(UserMetricsAction("PDF_ReaderInterstitialShown"));
168 interstitial_page_ = InterstitialPage::Create(
169 web_contents, false, web_contents->GetURL(), this);
170 interstitial_page_->Show();
173 protected:
174 // InterstitialPageDelegate implementation.
175 virtual std::string GetHTMLContents() OVERRIDE {
176 base::DictionaryValue strings;
177 strings.SetString(
178 "title",
179 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_TITLE));
180 strings.SetString(
181 "headLine",
182 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_BODY));
183 strings.SetString(
184 "update",
185 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_UPDATE));
186 strings.SetString(
187 "open_with_reader",
188 l10n_util::GetStringUTF16(
189 IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_PROCEED));
190 strings.SetString(
191 "ok",
192 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_OK));
193 strings.SetString(
194 "cancel",
195 l10n_util::GetStringUTF16(IDS_READER_OUT_OF_DATE_BLOCKING_PAGE_CANCEL));
197 base::StringPiece html(ResourceBundle::GetSharedInstance().
198 GetRawDataResource(IDR_READER_OUT_OF_DATE_HTML));
200 return webui::GetI18nTemplateHtml(html, &strings);
203 virtual void CommandReceived(const std::string& command) OVERRIDE {
204 if (command == "0") {
205 content::RecordAction(
206 UserMetricsAction("PDF_ReaderInterstitialCancel"));
207 interstitial_page_->DontProceed();
208 return;
211 if (command == "1") {
212 content::RecordAction(
213 UserMetricsAction("PDF_ReaderInterstitialUpdate"));
214 OpenReaderUpdateURL(web_contents_);
215 } else if (command == "2") {
216 content::RecordAction(
217 UserMetricsAction("PDF_ReaderInterstitialIgnore"));
218 // Pretend that the plug-in is up-to-date so that we don't block it.
219 reader_webplugininfo_.version = base::ASCIIToUTF16("11.0.0.0");
220 OpenUsingReader(web_contents_, reader_webplugininfo_, NULL);
221 } else {
222 NOTREACHED();
224 interstitial_page_->Proceed();
227 virtual void OverrideRendererPrefs(
228 content::RendererPreferences* prefs) OVERRIDE {
229 Profile* profile =
230 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
231 renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
234 private:
235 WebContents* web_contents_;
236 WebPluginInfo reader_webplugininfo_;
237 InterstitialPage* interstitial_page_; // Owns us.
239 DISALLOW_COPY_AND_ASSIGN(PDFUnsupportedFeatureInterstitial);
242 // The delegate for the bubble used to inform the user that we don't support a
243 // feature in the PDF.
244 class PDFUnsupportedFeaturePromptDelegate
245 : public OpenPDFInReaderPromptDelegate {
246 public:
247 // |reader| is NULL if Adobe Reader isn't installed.
248 PDFUnsupportedFeaturePromptDelegate(WebContents* web_contents,
249 const content::WebPluginInfo* reader,
250 PluginFinder* plugin_finder);
251 virtual ~PDFUnsupportedFeaturePromptDelegate();
253 // OpenPDFInReaderPromptDelegate:
254 virtual base::string16 GetMessageText() const OVERRIDE;
255 virtual base::string16 GetAcceptButtonText() const OVERRIDE;
256 virtual base::string16 GetCancelButtonText() const OVERRIDE;
257 virtual bool ShouldExpire(
258 const content::LoadCommittedDetails& details) const OVERRIDE;
259 virtual void Accept() OVERRIDE;
260 virtual void Cancel() OVERRIDE;
262 private:
263 WebContents* web_contents_;
264 bool reader_installed_;
265 bool reader_vulnerable_;
266 WebPluginInfo reader_webplugininfo_;
268 DISALLOW_IMPLICIT_CONSTRUCTORS(PDFUnsupportedFeaturePromptDelegate);
271 PDFUnsupportedFeaturePromptDelegate::PDFUnsupportedFeaturePromptDelegate(
272 WebContents* web_contents,
273 const content::WebPluginInfo* reader,
274 PluginFinder* plugin_finder)
275 : web_contents_(web_contents),
276 reader_installed_(!!reader),
277 reader_vulnerable_(false) {
278 if (!reader_installed_) {
279 content::RecordAction(
280 UserMetricsAction("PDF_InstallReaderInfoBarShown"));
281 return;
284 content::RecordAction(UserMetricsAction("PDF_UseReaderInfoBarShown"));
285 reader_webplugininfo_ = *reader;
287 #if defined(ENABLE_PLUGIN_INSTALLATION)
288 scoped_ptr<PluginMetadata> plugin_metadata(
289 plugin_finder->GetPluginMetadata(reader_webplugininfo_));
291 reader_vulnerable_ = plugin_metadata->GetSecurityStatus(*reader) !=
292 PluginMetadata::SECURITY_STATUS_UP_TO_DATE;
293 #else
294 NOTREACHED();
295 #endif
298 PDFUnsupportedFeaturePromptDelegate::~PDFUnsupportedFeaturePromptDelegate() {
301 base::string16 PDFUnsupportedFeaturePromptDelegate::GetMessageText() const {
302 return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_MESSAGE);
305 base::string16 PDFUnsupportedFeaturePromptDelegate::GetAcceptButtonText()
306 const {
307 #if defined(OS_WIN)
308 if (base::win::IsMetroProcess())
309 return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_METRO_MODE_LINK);
310 #endif
312 if (reader_installed_)
313 return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_OPEN_IN_READER_LINK);
315 return l10n_util::GetStringUTF16(IDS_PDF_BUBBLE_INSTALL_READER_LINK);
318 base::string16 PDFUnsupportedFeaturePromptDelegate::GetCancelButtonText()
319 const {
320 return l10n_util::GetStringUTF16(IDS_DONE);
323 bool PDFUnsupportedFeaturePromptDelegate::ShouldExpire(
324 const content::LoadCommittedDetails& details) const {
325 return !details.is_in_page;
328 void PDFUnsupportedFeaturePromptDelegate::Accept() {
329 #if defined(OS_WIN)
330 if (base::win::IsMetroProcess()) {
331 chrome::AttemptRestartWithModeSwitch();
332 return;
334 #endif
336 if (!reader_installed_) {
337 content::RecordAction(UserMetricsAction("PDF_InstallReaderInfoBarOK"));
338 OpenReaderUpdateURL(web_contents_);
339 return;
342 content::RecordAction(UserMetricsAction("PDF_UseReaderInfoBarOK"));
344 if (reader_vulnerable_) {
345 new PDFUnsupportedFeatureInterstitial(web_contents_, reader_webplugininfo_);
346 return;
349 Profile* profile =
350 Profile::FromBrowserContext(web_contents_->GetBrowserContext());
351 OpenPDFInReaderPromptDelegate* delegate =
352 new PDFEnableAdobeReaderPromptDelegate(profile);
354 OpenUsingReader(web_contents_, reader_webplugininfo_, delegate);
357 void PDFUnsupportedFeaturePromptDelegate::Cancel() {
358 content::RecordAction(reader_installed_ ?
359 UserMetricsAction("PDF_UseReaderInfoBarCancel") :
360 UserMetricsAction("PDF_InstallReaderInfoBarCancel"));
363 #if defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
364 void GotPluginsCallback(int process_id,
365 int routing_id,
366 const std::vector<content::WebPluginInfo>& plugins) {
367 WebContents* web_contents =
368 tab_util::GetWebContentsByID(process_id, routing_id);
369 if (!web_contents)
370 return;
372 const content::WebPluginInfo* reader = NULL;
373 PluginFinder* plugin_finder = PluginFinder::GetInstance();
374 for (size_t i = 0; i < plugins.size(); ++i) {
375 scoped_ptr<PluginMetadata> plugin_metadata(
376 plugin_finder->GetPluginMetadata(plugins[i]));
377 if (plugin_metadata->identifier() != kAdobeReaderIdentifier)
378 continue;
380 DCHECK(!reader);
381 reader = &plugins[i];
382 // If the Reader plugin is disabled by policy, don't prompt them.
383 Profile* profile =
384 Profile::FromBrowserContext(web_contents->GetBrowserContext());
385 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile);
386 if (plugin_prefs->PolicyStatusForPlugin(plugin_metadata->name()) ==
387 PluginPrefs::POLICY_DISABLED) {
388 return;
390 break;
393 scoped_ptr<OpenPDFInReaderPromptDelegate> prompt(
394 new PDFUnsupportedFeaturePromptDelegate(
395 web_contents, reader, plugin_finder));
396 PDFTabHelper* pdf_tab_helper = PDFTabHelper::FromWebContents(web_contents);
397 pdf_tab_helper->ShowOpenInReaderPrompt(prompt.Pass());
399 #endif // defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
401 } // namespace
403 void PDFHasUnsupportedFeature(content::WebContents* web_contents) {
404 #if defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
405 // Only works for Windows for now. For Mac, we'll have to launch the file
406 // externally since Adobe Reader doesn't work inside Chrome.
407 PluginService::GetInstance()->GetPlugins(base::Bind(&GotPluginsCallback,
408 web_contents->GetRenderProcessHost()->GetID(),
409 web_contents->GetRenderViewHost()->GetRoutingID()));
410 #endif