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.
4
5 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
6
7 #include <ctype.h>
8
9 #include <map>
10 #include <string>
11
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/command_line.h"
16 #include "base/i18n/file_util_icu.h"
17 #include "base/i18n/number_formatting.h"
18 #include "base/json/json_reader.h"
19 #include "base/lazy_instance.h"
20 #include "base/memory/linked_ptr.h"
21 #include "base/memory/ref_counted_memory.h"
22 #include "base/metrics/histogram.h"
23 #include "base/path_service.h"
24 #include "base/prefs/pref_service.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "base/threading/thread.h"
28 #include "base/threading/thread_restrictions.h"
29 #include "base/values.h"
30 #include "chrome/browser/browser_process.h"
31 #include "chrome/browser/platform_util.h"
32 #include "chrome/browser/printing/print_dialog_cloud.h"
33 #include "chrome/browser/printing/print_error_dialog.h"
34 #include "chrome/browser/printing/print_job_manager.h"
35 #include "chrome/browser/printing/print_preview_dialog_controller.h"
36 #include "chrome/browser/printing/print_view_manager.h"
37 #include "chrome/browser/printing/printer_manager_dialog.h"
38 #include "chrome/browser/profiles/profile.h"
39 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
40 #include "chrome/browser/signin/signin_manager_factory.h"
41 #include "chrome/browser/ui/browser_finder.h"
42 #include "chrome/browser/ui/browser_tabstrip.h"
43 #include "chrome/browser/ui/chrome_select_file_policy.h"
44 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
45 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
46 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
47 #include "chrome/common/chrome_paths.h"
48 #include "chrome/common/chrome_switches.h"
49 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
50 #include "chrome/common/cloud_print/cloud_print_constants.h"
51 #include "chrome/common/crash_keys.h"
52 #include "chrome/common/pref_names.h"
53 #include "chrome/common/print_messages.h"
54 #include "components/cloud_devices/common/cloud_device_description.h"
55 #include "components/cloud_devices/common/cloud_devices_urls.h"
56 #include "components/cloud_devices/common/printer_description.h"
57 #include "components/signin/core/browser/profile_oauth2_token_service.h"
58 #include "components/signin/core/browser/signin_manager.h"
59 #include "components/signin/core/browser/signin_manager_base.h"
60 #include "content/public/browser/browser_context.h"
61 #include "content/public/browser/browser_thread.h"
62 #include "content/public/browser/navigation_controller.h"
63 #include "content/public/browser/navigation_entry.h"
64 #include "content/public/browser/render_view_host.h"
65 #include "content/public/browser/web_contents.h"
66 #include "content/public/browser/web_ui.h"
67 #include "google_apis/gaia/oauth2_token_service.h"
68 #include "printing/backend/print_backend.h"
69 #include "printing/backend/print_backend_consts.h"
70 #include "printing/metafile.h"
71 #include "printing/metafile_impl.h"
72 #include "printing/pdf_render_settings.h"
73 #include "printing/print_settings.h"
74 #include "printing/printing_context.h"
75 #include "printing/units.h"
76 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
77
78 #if defined(OS_CHROMEOS)
79 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
80 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
81 #endif
82
83 #if defined(ENABLE_SERVICE_DISCOVERY)
84 #include "chrome/browser/local_discovery/privet_constants.h"
85 #endif
86
87 using content::BrowserThread;
88 using content::RenderViewHost;
89 using content::WebContents;
90
91 namespace {
92
93 enum UserActionBuckets {
94 PRINT_TO_PRINTER,
95 PRINT_TO_PDF,
96 CANCEL,
97 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
98 PREVIEW_FAILED,
99 PREVIEW_STARTED,
100 INITIATOR_CRASHED, // UNUSED
101 INITIATOR_CLOSED,
102 PRINT_WITH_CLOUD_PRINT,
103 PRINT_WITH_PRIVET,
104 USERACTION_BUCKET_BOUNDARY
105 };
106
107 enum PrintSettingsBuckets {
108 LANDSCAPE = 0,
109 PORTRAIT,
110 COLOR,
111 BLACK_AND_WHITE,
112 COLLATE,
113 SIMPLEX,
114 DUPLEX,
115 TOTAL,
116 HEADERS_AND_FOOTERS,
117 CSS_BACKGROUND,
118 SELECTION_ONLY,
119 EXTERNAL_PDF_PREVIEW,
120 PRINT_SETTINGS_BUCKET_BOUNDARY
121 };
122
123 enum UiBucketGroups {
124 DESTINATION_SEARCH,
125 GCP_PROMO,
126 UI_BUCKET_GROUP_BOUNDARY
127 };
128
129 enum PrintDestinationBuckets {
130 DESTINATION_SHOWN,
131 DESTINATION_CLOSED_CHANGED,
132 DESTINATION_CLOSED_UNCHANGED,
133 SIGNIN_PROMPT,
134 SIGNIN_TRIGGERED,
135 PRIVET_DUPLICATE_SELECTED,
136 CLOUD_DUPLICATE_SELECTED,
137 REGISTER_PROMO_SHOWN,
138 REGISTER_PROMO_SELECTED,
139 ACCOUNT_CHANGED,
140 ADD_ACCOUNT_SELECTED,
141 PRINT_DESTINATION_BUCKET_BOUNDARY
142 };
143
144 enum GcpPromoBuckets {
145 PROMO_SHOWN,
146 PROMO_CLOSED,
147 PROMO_CLICKED,
148 GCP_PROMO_BUCKET_BOUNDARY
149 };
150
ReportUserActionHistogram(enum UserActionBuckets event)151 void ReportUserActionHistogram(enum UserActionBuckets event) {
152 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
153 USERACTION_BUCKET_BOUNDARY);
154 }
155
ReportPrintSettingHistogram(enum PrintSettingsBuckets setting)156 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
157 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
158 PRINT_SETTINGS_BUCKET_BOUNDARY);
159 }
160
ReportPrintDestinationHistogram(enum PrintDestinationBuckets event)161 void ReportPrintDestinationHistogram(enum PrintDestinationBuckets event) {
162 UMA_HISTOGRAM_ENUMERATION("PrintPreview.DestinationAction", event,
163 PRINT_DESTINATION_BUCKET_BOUNDARY);
164 }
165
ReportGcpPromoHistogram(enum GcpPromoBuckets event)166 void ReportGcpPromoHistogram(enum GcpPromoBuckets event) {
167 UMA_HISTOGRAM_ENUMERATION("PrintPreview.GcpPromo", event,
168 GCP_PROMO_BUCKET_BOUNDARY);
169 }
170
171 // Name of a dictionary field holding cloud print related data;
172 const char kAppState[] = "appState";
173 // Name of a dictionary field holding the initiator title.
174 const char kInitiatorTitle[] = "initiatorTitle";
175 // Name of a dictionary field holding the measurement system according to the
176 // locale.
177 const char kMeasurementSystem[] = "measurementSystem";
178 // Name of a dictionary field holding the number format according to the locale.
179 const char kNumberFormat[] = "numberFormat";
180 // Name of a dictionary field specifying whether to print automatically in
181 // kiosk mode. See http://crbug.com/31395.
182 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
183 #if defined(OS_WIN)
184 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
185 #endif
186 // Name of a dictionary field holding the state of selection for document.
187 const char kDocumentHasSelection[] = "documentHasSelection";
188
189 // Id of the predefined PDF printer.
190 const char kLocalPdfPrinterId[] = "Save as PDF";
191
192 // Additional printer capability setting keys.
193 const char kPrinterId[] = "printerId";
194 const char kPrinterCapabilities[] = "capabilities";
195
196 // Get the print job settings dictionary from |args|. The caller takes
197 // ownership of the returned DictionaryValue. Returns NULL on failure.
GetSettingsDictionary(const base::ListValue * args)198 base::DictionaryValue* GetSettingsDictionary(const base::ListValue* args) {
199 std::string json_str;
200 if (!args->GetString(0, &json_str)) {
201 NOTREACHED() << "Could not read JSON argument";
202 return NULL;
203 }
204 if (json_str.empty()) {
205 NOTREACHED() << "Empty print job settings";
206 return NULL;
207 }
208 scoped_ptr<base::DictionaryValue> settings(
209 static_cast<base::DictionaryValue*>(
210 base::JSONReader::Read(json_str)));
211 if (!settings.get() || !settings->IsType(base::Value::TYPE_DICTIONARY)) {
212 NOTREACHED() << "Print job settings must be a dictionary.";
213 return NULL;
214 }
215
216 if (settings->empty()) {
217 NOTREACHED() << "Print job settings dictionary is empty";
218 return NULL;
219 }
220
221 return settings.release();
222 }
223
224 // Track the popularity of print settings and report the stats.
ReportPrintSettingsStats(const base::DictionaryValue & settings)225 void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
226 ReportPrintSettingHistogram(TOTAL);
227
228 bool landscape = false;
229 if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
230 ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
231
232 bool collate = false;
233 if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
234 ReportPrintSettingHistogram(COLLATE);
235
236 int duplex_mode = 0;
237 if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
238 ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
239
240 int color_mode = 0;
241 if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
242 ReportPrintSettingHistogram(
243 printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
244 }
245
246 bool headers = false;
247 if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
248 headers) {
249 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
250 }
251
252 bool css_background = false;
253 if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
254 &css_background) && css_background) {
255 ReportPrintSettingHistogram(CSS_BACKGROUND);
256 }
257
258 bool selection_only = false;
259 if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
260 &selection_only) && selection_only) {
261 ReportPrintSettingHistogram(SELECTION_ONLY);
262 }
263
264 bool external_preview = false;
265 if (settings.GetBoolean(printing::kSettingOpenPDFInPreview,
266 &external_preview) && external_preview) {
267 ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW);
268 }
269 }
270
271 // Callback that stores a PDF file on disk.
PrintToPdfCallback(printing::Metafile * metafile,const base::FilePath & path)272 void PrintToPdfCallback(printing::Metafile* metafile,
273 const base::FilePath& path) {
274 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
275 metafile->SaveTo(path);
276 // |metafile| must be deleted on the UI thread.
277 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, metafile);
278 }
279
GetDefaultPrinterOnFileThread()280 std::string GetDefaultPrinterOnFileThread() {
281 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
282
283 scoped_refptr<printing::PrintBackend> print_backend(
284 printing::PrintBackend::CreateInstance(NULL));
285
286 std::string default_printer = print_backend->GetDefaultPrinterName();
287 VLOG(1) << "Default Printer: " << default_printer;
288 return default_printer;
289 }
290
GetDefaultPdfMediaSizeMicrons()291 gfx::Size GetDefaultPdfMediaSizeMicrons() {
292 scoped_ptr<printing::PrintingContext> printing_context(
293 printing::PrintingContext::Create(
294 g_browser_process->GetApplicationLocale()));
295 if (printing::PrintingContext::OK != printing_context->UsePdfSettings() ||
296 printing_context->settings().device_units_per_inch() <= 0) {
297 return gfx::Size();
298 }
299 gfx::Size pdf_media_size = printing_context->GetPdfPaperSizeDeviceUnits();
300 float deviceMicronsPerDeviceUnit =
301 (printing::kHundrethsMMPerInch * 10.0f) /
302 printing_context->settings().device_units_per_inch();
303 return gfx::Size(pdf_media_size.width() * deviceMicronsPerDeviceUnit,
304 pdf_media_size.height() * deviceMicronsPerDeviceUnit);
305 }
306
307 typedef base::Callback<void(const base::DictionaryValue*)>
308 GetPdfCapabilitiesCallback;
309
GetPdfCapabilitiesOnFileThread(const std::string & locale)310 scoped_ptr<base::DictionaryValue> GetPdfCapabilitiesOnFileThread(
311 const std::string& locale) {
312 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
313
314 cloud_devices::CloudDeviceDescription description;
315 using namespace cloud_devices::printer;
316
317 OrientationCapability orientation;
318 orientation.AddOption(cloud_devices::printer::PORTRAIT);
319 orientation.AddOption(cloud_devices::printer::LANDSCAPE);
320 orientation.AddDefaultOption(AUTO_ORIENTATION, true);
321 orientation.SaveTo(&description);
322
323 ColorCapability color;
324 {
325 Color standard_color(STANDARD_COLOR);
326 standard_color.vendor_id = base::IntToString(printing::COLOR);
327 color.AddDefaultOption(standard_color, true);
328 }
329 color.SaveTo(&description);
330
331 static const cloud_devices::printer::MediaType kPdfMedia[] = {
332 ISO_A4,
333 ISO_A3,
334 NA_LETTER,
335 NA_LEGAL,
336 NA_LEDGER
337 };
338 const gfx::Size default_media_size = GetDefaultPdfMediaSizeMicrons();
339 Media default_media(
340 "", "", default_media_size.width(), default_media_size.height());
341 if (!default_media.MatchBySize() ||
342 std::find(kPdfMedia,
343 kPdfMedia + arraysize(kPdfMedia),
344 default_media.type) == kPdfMedia + arraysize(kPdfMedia)) {
345 default_media = Media(locale == "en-US" ? NA_LETTER : ISO_A4);
346 }
347 MediaCapability media;
348 for (size_t i = 0; i < arraysize(kPdfMedia); ++i) {
349 Media media_option(kPdfMedia[i]);
350 media.AddDefaultOption(media_option,
351 default_media.type == media_option.type);
352 }
353 media.SaveTo(&description);
354
355 return scoped_ptr<base::DictionaryValue>(description.root().DeepCopy());
356 }
357
GetLocalPrinterCapabilitiesOnFileThread(const std::string & printer_name)358 scoped_ptr<base::DictionaryValue> GetLocalPrinterCapabilitiesOnFileThread(
359 const std::string& printer_name) {
360 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
361
362 scoped_refptr<printing::PrintBackend> print_backend(
363 printing::PrintBackend::CreateInstance(NULL));
364
365 VLOG(1) << "Get printer capabilities start for " << printer_name;
366 crash_keys::ScopedPrinterInfo crash_key(
367 print_backend->GetPrinterDriverInfo(printer_name));
368
369 if (!print_backend->IsValidPrinter(printer_name)) {
370 LOG(WARNING) << "Invalid printer " << printer_name;
371 return scoped_ptr<base::DictionaryValue>();
372 }
373
374 printing::PrinterSemanticCapsAndDefaults info;
375 if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
376 LOG(WARNING) << "Failed to get capabilities for " << printer_name;
377 return scoped_ptr<base::DictionaryValue>();
378 }
379
380 scoped_ptr<base::DictionaryValue> description(
381 cloud_print::PrinterSemanticCapsAndDefaultsToCdd(info));
382 if (!description) {
383 LOG(WARNING) << "Failed to convert capabilities for " << printer_name;
384 return scoped_ptr<base::DictionaryValue>();
385 }
386
387 return description.Pass();
388 }
389
EnumeratePrintersOnFileThread(base::ListValue * printers)390 void EnumeratePrintersOnFileThread(base::ListValue* printers) {
391 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
392
393 scoped_refptr<printing::PrintBackend> print_backend(
394 printing::PrintBackend::CreateInstance(NULL));
395
396 VLOG(1) << "Enumerate printers start";
397 printing::PrinterList printer_list;
398 print_backend->EnumeratePrinters(&printer_list);
399
400 for (printing::PrinterList::iterator it = printer_list.begin();
401 it != printer_list.end(); ++it) {
402 base::DictionaryValue* printer_info = new base::DictionaryValue;
403 printers->Append(printer_info);
404 std::string printer_name;
405 std::string printer_description;
406 #if defined(OS_MACOSX)
407 // On Mac, |it->printer_description| specifies the printer name and
408 // |it->printer_name| specifies the device name / printer queue name.
409 printer_name = it->printer_description;
410 if (!it->options[kDriverNameTagName].empty())
411 printer_description = it->options[kDriverNameTagName];
412 #else
413 printer_name = it->printer_name;
414 printer_description = it->printer_description;
415 #endif
416 printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
417 printer_info->SetString(printing::kSettingPrinterDescription,
418 printer_description);
419 printer_info->SetString(printing::kSettingPrinterName, printer_name);
420 VLOG(1) << "Found printer " << printer_name
421 << " with device name " << it->printer_name;
422
423 base::DictionaryValue* options = new base::DictionaryValue;
424 printer_info->Set(printing::kSettingPrinterOptions, options);
425 for (std::map<std::string, std::string>::iterator opt = it->options.begin();
426 opt != it->options.end();
427 ++opt) {
428 options->SetString(opt->first, opt->second);
429 }
430
431 VLOG(1) << "Found printer " << printer_name << " with device name "
432 << it->printer_name;
433 }
434 VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
435 << " printers";
436 }
437
438 typedef base::Callback<void(const base::DictionaryValue*)>
439 GetPrinterCapabilitiesSuccessCallback;
440 typedef base::Callback<void(const std::string&)>
441 GetPrinterCapabilitiesFailureCallback;
442
GetPrinterCapabilitiesOnFileThread(const std::string & printer_name,const std::string & locale,const GetPrinterCapabilitiesSuccessCallback & success_cb,const GetPrinterCapabilitiesFailureCallback & failure_cb)443 void GetPrinterCapabilitiesOnFileThread(
444 const std::string& printer_name,
445 const std::string& locale,
446 const GetPrinterCapabilitiesSuccessCallback& success_cb,
447 const GetPrinterCapabilitiesFailureCallback& failure_cb) {
448 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
449 DCHECK(!printer_name.empty());
450
451 scoped_ptr<base::DictionaryValue> printer_capabilities(
452 printer_name == kLocalPdfPrinterId ?
453 GetPdfCapabilitiesOnFileThread(locale) :
454 GetLocalPrinterCapabilitiesOnFileThread(printer_name));
455 if (!printer_capabilities) {
456 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
457 base::Bind(failure_cb, printer_name));
458 return;
459 }
460
461 scoped_ptr<base::DictionaryValue> printer_info(new base::DictionaryValue);
462 printer_info->SetString(kPrinterId, printer_name);
463 printer_info->Set(kPrinterCapabilities, printer_capabilities.release());
464
465 BrowserThread::PostTask(
466 BrowserThread::UI, FROM_HERE,
467 base::Bind(success_cb, base::Owned(printer_info.release())));
468 }
469
470 base::LazyInstance<printing::StickySettings> g_sticky_settings =
471 LAZY_INSTANCE_INITIALIZER;
472
GetStickySettings()473 printing::StickySettings* GetStickySettings() {
474 return g_sticky_settings.Pointer();
475 }
476
477 } // namespace
478
479 class PrintPreviewHandler::AccessTokenService
480 : public OAuth2TokenService::Consumer {
481 public:
AccessTokenService(PrintPreviewHandler * handler)482 explicit AccessTokenService(PrintPreviewHandler* handler)
483 : OAuth2TokenService::Consumer("print_preview"),
484 handler_(handler) {
485 }
486
RequestToken(const std::string & type)487 void RequestToken(const std::string& type) {
488 if (requests_.find(type) != requests_.end())
489 return; // Already in progress.
490
491 OAuth2TokenService* service = NULL;
492 std::string account_id;
493 if (type == "profile") {
494 Profile* profile = Profile::FromWebUI(handler_->web_ui());
495 if (profile) {
496 ProfileOAuth2TokenService* token_service =
497 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
498 SigninManagerBase* signin_manager =
499 SigninManagerFactory::GetInstance()->GetForProfile(profile);
500 account_id = signin_manager->GetAuthenticatedAccountId();
501 service = token_service;
502 }
503 } else if (type == "device") {
504 #if defined(OS_CHROMEOS)
505 chromeos::DeviceOAuth2TokenService* token_service =
506 chromeos::DeviceOAuth2TokenServiceFactory::Get();
507 account_id = token_service->GetRobotAccountId();
508 service = token_service;
509 #endif
510 }
511
512 if (service) {
513 OAuth2TokenService::ScopeSet oauth_scopes;
514 oauth_scopes.insert(cloud_devices::kCloudPrintAuthScope);
515 scoped_ptr<OAuth2TokenService::Request> request(
516 service->StartRequest(account_id, oauth_scopes, this));
517 requests_[type].reset(request.release());
518 } else {
519 handler_->SendAccessToken(type, std::string()); // Unknown type.
520 }
521 }
522
OnGetTokenSuccess(const OAuth2TokenService::Request * request,const std::string & access_token,const base::Time & expiration_time)523 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
524 const std::string& access_token,
525 const base::Time& expiration_time) OVERRIDE {
526 OnServiceResponce(request, access_token);
527 }
528
OnGetTokenFailure(const OAuth2TokenService::Request * request,const GoogleServiceAuthError & error)529 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
530 const GoogleServiceAuthError& error) OVERRIDE {
531 OnServiceResponce(request, std::string());
532 }
533
534 private:
OnServiceResponce(const OAuth2TokenService::Request * request,const std::string & access_token)535 void OnServiceResponce(const OAuth2TokenService::Request* request,
536 const std::string& access_token) {
537 for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
538 if (i->second == request) {
539 handler_->SendAccessToken(i->first, access_token);
540 requests_.erase(i);
541 return;
542 }
543 }
544 NOTREACHED();
545 }
546
547 typedef std::map<std::string,
548 linked_ptr<OAuth2TokenService::Request> > Requests;
549 Requests requests_;
550 PrintPreviewHandler* handler_;
551
552 DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
553 };
554
PrintPreviewHandler()555 PrintPreviewHandler::PrintPreviewHandler()
556 : regenerate_preview_request_count_(0),
557 manage_printers_dialog_request_count_(0),
558 manage_cloud_printers_dialog_request_count_(0),
559 reported_failed_preview_(false),
560 has_logged_printers_count_(false),
561 weak_factory_(this) {
562 ReportUserActionHistogram(PREVIEW_STARTED);
563 }
564
~PrintPreviewHandler()565 PrintPreviewHandler::~PrintPreviewHandler() {
566 if (select_file_dialog_.get())
567 select_file_dialog_->ListenerDestroyed();
568 }
569
RegisterMessages()570 void PrintPreviewHandler::RegisterMessages() {
571 web_ui()->RegisterMessageCallback("getPrinters",
572 base::Bind(&PrintPreviewHandler::HandleGetPrinters,
573 base::Unretained(this)));
574 web_ui()->RegisterMessageCallback("getPreview",
575 base::Bind(&PrintPreviewHandler::HandleGetPreview,
576 base::Unretained(this)));
577 web_ui()->RegisterMessageCallback("print",
578 base::Bind(&PrintPreviewHandler::HandlePrint,
579 base::Unretained(this)));
580 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
581 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
582 base::Unretained(this)));
583 web_ui()->RegisterMessageCallback("showSystemDialog",
584 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
585 base::Unretained(this)));
586 web_ui()->RegisterMessageCallback("signIn",
587 base::Bind(&PrintPreviewHandler::HandleSignin,
588 base::Unretained(this)));
589 web_ui()->RegisterMessageCallback("getAccessToken",
590 base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
591 base::Unretained(this)));
592 web_ui()->RegisterMessageCallback("manageCloudPrinters",
593 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
594 base::Unretained(this)));
595 web_ui()->RegisterMessageCallback("manageLocalPrinters",
596 base::Bind(&PrintPreviewHandler::HandleManagePrinters,
597 base::Unretained(this)));
598 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
599 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
600 base::Unretained(this)));
601 web_ui()->RegisterMessageCallback("hidePreview",
602 base::Bind(&PrintPreviewHandler::HandleHidePreview,
603 base::Unretained(this)));
604 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
605 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
606 base::Unretained(this)));
607 web_ui()->RegisterMessageCallback("saveAppState",
608 base::Bind(&PrintPreviewHandler::HandleSaveAppState,
609 base::Unretained(this)));
610 web_ui()->RegisterMessageCallback("getInitialSettings",
611 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
612 base::Unretained(this)));
613 web_ui()->RegisterMessageCallback("reportUiEvent",
614 base::Bind(&PrintPreviewHandler::HandleReportUiEvent,
615 base::Unretained(this)));
616 web_ui()->RegisterMessageCallback("printWithCloudPrintDialog",
617 base::Bind(&PrintPreviewHandler::HandlePrintWithCloudPrintDialog,
618 base::Unretained(this)));
619 web_ui()->RegisterMessageCallback("forceOpenNewTab",
620 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
621 base::Unretained(this)));
622 web_ui()->RegisterMessageCallback("getPrivetPrinters",
623 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
624 base::Unretained(this)));
625 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
626 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
627 base::Unretained(this)));
628 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
629 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
630 base::Unretained(this)));
631 }
632
PrivetPrintingEnabled()633 bool PrintPreviewHandler::PrivetPrintingEnabled() {
634 #if defined(ENABLE_SERVICE_DISCOVERY)
635 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
636 switches::kDisableDeviceDiscovery);
637 #else
638 return false;
639 #endif
640 }
641
preview_web_contents() const642 WebContents* PrintPreviewHandler::preview_web_contents() const {
643 return web_ui()->GetWebContents();
644 }
645
HandleGetPrinters(const base::ListValue *)646 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
647 base::ListValue* results = new base::ListValue;
648 BrowserThread::PostTaskAndReply(
649 BrowserThread::FILE, FROM_HERE,
650 base::Bind(&EnumeratePrintersOnFileThread,
651 base::Unretained(results)),
652 base::Bind(&PrintPreviewHandler::SetupPrinterList,
653 weak_factory_.GetWeakPtr(),
654 base::Owned(results)));
655 }
656
HandleGetPrivetPrinters(const base::ListValue * args)657 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
658 #if defined(ENABLE_SERVICE_DISCOVERY)
659 if (PrivetPrintingEnabled()) {
660 Profile* profile = Profile::FromWebUI(web_ui());
661 service_discovery_client_ =
662 local_discovery::ServiceDiscoverySharedClient::GetInstance();
663 printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
664 service_discovery_client_.get(),
665 profile->GetRequestContext(),
666 this));
667 printer_lister_->Start();
668 }
669 #endif
670
671 if (!PrivetPrintingEnabled()) {
672 web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
673 }
674 }
675
HandleStopGetPrivetPrinters(const base::ListValue * args)676 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
677 const base::ListValue* args) {
678 #if defined(ENABLE_SERVICE_DISCOVERY)
679 if (PrivetPrintingEnabled()) {
680 printer_lister_->Stop();
681 }
682 #endif
683 }
684
HandleGetPrivetPrinterCapabilities(const base::ListValue * args)685 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
686 const base::ListValue* args) {
687 #if defined(ENABLE_SERVICE_DISCOVERY)
688 std::string name;
689 bool success = args->GetString(0, &name);
690 DCHECK(success);
691
692 CreatePrivetHTTP(
693 name,
694 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
695 base::Unretained(this)));
696 #endif
697 }
698
HandleGetPreview(const base::ListValue * args)699 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
700 DCHECK_EQ(3U, args->GetSize());
701 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
702 if (!settings.get())
703 return;
704 int request_id = -1;
705 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
706 return;
707
708 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
709 web_ui()->GetController());
710 print_preview_ui->OnPrintPreviewRequest(request_id);
711 // Add an additional key in order to identify |print_preview_ui| later on
712 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
713 // thread.
714 settings->SetInteger(printing::kPreviewUIID,
715 print_preview_ui->GetIDForPrintPreviewUI());
716
717 // Increment request count.
718 ++regenerate_preview_request_count_;
719
720 WebContents* initiator = GetInitiator();
721 if (!initiator) {
722 ReportUserActionHistogram(INITIATOR_CLOSED);
723 print_preview_ui->OnClosePrintPreviewDialog();
724 return;
725 }
726
727 // Retrieve the page title and url and send it to the renderer process if
728 // headers and footers are to be displayed.
729 bool display_header_footer = false;
730 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
731 &display_header_footer)) {
732 NOTREACHED();
733 }
734 if (display_header_footer) {
735 settings->SetString(printing::kSettingHeaderFooterTitle,
736 initiator->GetTitle());
737 std::string url;
738 content::NavigationEntry* entry =
739 initiator->GetController().GetLastCommittedEntry();
740 if (entry)
741 url = entry->GetVirtualURL().spec();
742 settings->SetString(printing::kSettingHeaderFooterURL, url);
743 }
744
745 bool generate_draft_data = false;
746 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
747 &generate_draft_data);
748 DCHECK(success);
749
750 if (!generate_draft_data) {
751 double draft_page_count_double = -1;
752 success = args->GetDouble(1, &draft_page_count_double);
753 DCHECK(success);
754 int draft_page_count = static_cast<int>(draft_page_count_double);
755
756 bool preview_modifiable = false;
757 success = args->GetBoolean(2, &preview_modifiable);
758 DCHECK(success);
759
760 if (draft_page_count != -1 && preview_modifiable &&
761 print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
762 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
763 }
764 }
765
766 VLOG(1) << "Print preview request start";
767 RenderViewHost* rvh = initiator->GetRenderViewHost();
768 rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
769 }
770
HandlePrint(const base::ListValue * args)771 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
772 ReportStats();
773
774 // Record the number of times the user requests to regenerate preview data
775 // before printing.
776 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
777 regenerate_preview_request_count_);
778
779 WebContents* initiator = GetInitiator();
780 if (initiator) {
781 RenderViewHost* rvh = initiator->GetRenderViewHost();
782 rvh->Send(new PrintMsg_ResetScriptedPrintCount(rvh->GetRoutingID()));
783 }
784
785 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
786 if (!settings.get())
787 return;
788
789 // Never try to add headers/footers here. It's already in the generated PDF.
790 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
791
792 bool print_to_pdf = false;
793 bool is_cloud_printer = false;
794 bool print_with_privet = false;
795
796 bool open_pdf_in_preview = false;
797 #if defined(OS_MACOSX)
798 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
799 #endif
800
801 if (!open_pdf_in_preview) {
802 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
803 settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
804 is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
805 }
806
807 int page_count = 0;
808 settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
809
810 if (print_to_pdf) {
811 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
812 ReportUserActionHistogram(PRINT_TO_PDF);
813 PrintToPdf();
814 return;
815 }
816
817 #if defined(ENABLE_SERVICE_DISCOVERY)
818 if (print_with_privet && PrivetPrintingEnabled()) {
819 std::string printer_name;
820 std::string print_ticket;
821 std::string capabilities;
822 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
823 ReportUserActionHistogram(PRINT_WITH_PRIVET);
824
825 int width = 0;
826 int height = 0;
827 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
828 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
829 !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
830 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
831 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
832 width <= 0 || height <= 0) {
833 NOTREACHED();
834 base::FundamentalValue http_code_value(-1);
835 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
836 return;
837 }
838
839 PrintToPrivetPrinter(
840 printer_name, print_ticket, capabilities, gfx::Size(width, height));
841 return;
842 }
843 #endif
844
845 scoped_refptr<base::RefCountedBytes> data;
846 base::string16 title;
847 if (!GetPreviewDataAndTitle(&data, &title)) {
848 // Nothing to print, no preview available.
849 return;
850 }
851
852 if (is_cloud_printer) {
853 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
854 page_count);
855 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
856 SendCloudPrintJob(data.get());
857 } else {
858 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
859 ReportUserActionHistogram(PRINT_TO_PRINTER);
860 ReportPrintSettingsStats(*settings);
861
862 // This tries to activate the initiator as well, so do not clear the
863 // association with the initiator yet.
864 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
865 web_ui()->GetController());
866 print_preview_ui->OnHidePreviewDialog();
867
868 // Do this so the initiator can open a new print preview dialog, while the
869 // current print preview dialog is still handling its print job.
870 ClearInitiatorDetails();
871
872 // The PDF being printed contains only the pages that the user selected,
873 // so ignore the page range and print all pages.
874 settings->Remove(printing::kSettingPageRange, NULL);
875 // Reset selection only flag for the same reason.
876 settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
877
878 // Set ID to know whether printing is for preview.
879 settings->SetInteger(printing::kPreviewUIID,
880 print_preview_ui->GetIDForPrintPreviewUI());
881 RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
882 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
883 *settings));
884
885 // For all other cases above, the preview dialog will stay open until the
886 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
887 // called. In the case below, since the preview dialog will be hidden and
888 // not closed, we need to make this call.
889 if (initiator) {
890 printing::PrintViewManager* print_view_manager =
891 printing::PrintViewManager::FromWebContents(initiator);
892 print_view_manager->PrintPreviewDone();
893 }
894 }
895 }
896
PrintToPdf()897 void PrintPreviewHandler::PrintToPdf() {
898 if (!print_to_pdf_path_.empty()) {
899 // User has already selected a path, no need to show the dialog again.
900 PostPrintToPdfTask();
901 } else if (!select_file_dialog_.get() ||
902 !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
903 preview_web_contents()->GetNativeView()))) {
904 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
905 web_ui()->GetController());
906 // Pre-populating select file dialog with print job title.
907 base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
908
909 #if defined(OS_WIN)
910 base::FilePath::StringType print_job_title(print_job_title_utf16);
911 #elif defined(OS_POSIX)
912 base::FilePath::StringType print_job_title =
913 base::UTF16ToUTF8(print_job_title_utf16);
914 #endif
915
916 file_util::ReplaceIllegalCharactersInPath(&print_job_title, '_');
917 base::FilePath default_filename(print_job_title);
918 default_filename =
919 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
920
921 SelectFile(default_filename);
922 }
923 }
924
HandleHidePreview(const base::ListValue *)925 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
926 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
927 web_ui()->GetController());
928 print_preview_ui->OnHidePreviewDialog();
929 }
930
HandleCancelPendingPrintRequest(const base::ListValue *)931 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
932 const base::ListValue* /*args*/) {
933 WebContents* initiator = GetInitiator();
934 if (initiator)
935 ClearInitiatorDetails();
936 chrome::ShowPrintErrorDialog();
937 }
938
HandleSaveAppState(const base::ListValue * args)939 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
940 std::string data_to_save;
941 printing::StickySettings* sticky_settings = GetStickySettings();
942 if (args->GetString(0, &data_to_save) && !data_to_save.empty())
943 sticky_settings->StoreAppState(data_to_save);
944 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
945 preview_web_contents()->GetBrowserContext())->GetPrefs());
946 }
947
HandleGetPrinterCapabilities(const base::ListValue * args)948 void PrintPreviewHandler::HandleGetPrinterCapabilities(
949 const base::ListValue* args) {
950 std::string printer_name;
951 bool ret = args->GetString(0, &printer_name);
952 if (!ret || printer_name.empty())
953 return;
954
955 GetPrinterCapabilitiesSuccessCallback success_cb =
956 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
957 weak_factory_.GetWeakPtr());
958 GetPrinterCapabilitiesFailureCallback failure_cb =
959 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
960 weak_factory_.GetWeakPtr());
961 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
962 base::Bind(&GetPrinterCapabilitiesOnFileThread,
963 printer_name,
964 g_browser_process->GetApplicationLocale(),
965 success_cb, failure_cb));
966 }
967
OnSigninComplete()968 void PrintPreviewHandler::OnSigninComplete() {
969 PrintPreviewUI* print_preview_ui =
970 static_cast<PrintPreviewUI*>(web_ui()->GetController());
971 if (print_preview_ui)
972 print_preview_ui->OnReloadPrintersList();
973 }
974
HandleSignin(const base::ListValue * args)975 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
976 bool add_account = false;
977 bool success = args->GetBoolean(0, &add_account);
978 DCHECK(success);
979
980 Profile* profile = Profile::FromBrowserContext(
981 preview_web_contents()->GetBrowserContext());
982 chrome::ScopedTabbedBrowserDisplayer displayer(
983 profile, chrome::GetActiveDesktop());
984 print_dialog_cloud::CreateCloudPrintSigninTab(
985 displayer.browser(),
986 add_account,
987 base::Bind(&PrintPreviewHandler::OnSigninComplete,
988 weak_factory_.GetWeakPtr()));
989 }
990
HandleGetAccessToken(const base::ListValue * args)991 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
992 std::string type;
993 if (!args->GetString(0, &type))
994 return;
995 if (!token_service_)
996 token_service_.reset(new AccessTokenService(this));
997 token_service_->RequestToken(type);
998 }
999
PrintWithCloudPrintDialog()1000 void PrintPreviewHandler::PrintWithCloudPrintDialog() {
1001 // Record the number of times the user asks to print via cloud print
1002 // instead of the print preview dialog.
1003 ReportStats();
1004
1005 scoped_refptr<base::RefCountedBytes> data;
1006 base::string16 title;
1007 if (!GetPreviewDataAndTitle(&data, &title)) {
1008 // Nothing to print, no preview available.
1009 return;
1010 }
1011
1012 gfx::NativeWindow modal_parent = platform_util::GetTopLevel(
1013 preview_web_contents()->GetNativeView());
1014 print_dialog_cloud::CreatePrintDialogForBytes(
1015 preview_web_contents()->GetBrowserContext(),
1016 modal_parent,
1017 data.get(),
1018 title,
1019 base::string16(),
1020 std::string("application/pdf"));
1021
1022 // Once the cloud print dialog comes up we're no longer in a background
1023 // printing situation. Close the print preview.
1024 // TODO(abodenha@chromium.org) The flow should be changed as described in
1025 // http://code.google.com/p/chromium/issues/detail?id=44093
1026 ClosePreviewDialog();
1027 }
1028
HandleManageCloudPrint(const base::ListValue *)1029 void PrintPreviewHandler::HandleManageCloudPrint(
1030 const base::ListValue* /*args*/) {
1031 ++manage_cloud_printers_dialog_request_count_;
1032 preview_web_contents()->OpenURL(content::OpenURLParams(
1033 cloud_devices::GetCloudPrintRelativeURL("manage.html"),
1034 content::Referrer(),
1035 NEW_FOREGROUND_TAB,
1036 content::PAGE_TRANSITION_LINK,
1037 false));
1038 }
1039
HandleShowSystemDialog(const base::ListValue *)1040 void PrintPreviewHandler::HandleShowSystemDialog(
1041 const base::ListValue* /*args*/) {
1042 ReportStats();
1043 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1044
1045 WebContents* initiator = GetInitiator();
1046 if (!initiator)
1047 return;
1048
1049 printing::PrintViewManager* print_view_manager =
1050 printing::PrintViewManager::FromWebContents(initiator);
1051 print_view_manager->set_observer(this);
1052 print_view_manager->PrintForSystemDialogNow();
1053
1054 // Cancel the pending preview request if exists.
1055 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1056 web_ui()->GetController());
1057 print_preview_ui->OnCancelPendingPreviewRequest();
1058 }
1059
HandleManagePrinters(const base::ListValue *)1060 void PrintPreviewHandler::HandleManagePrinters(
1061 const base::ListValue* /*args*/) {
1062 ++manage_printers_dialog_request_count_;
1063 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1064 }
1065
HandlePrintWithCloudPrintDialog(const base::ListValue * args)1066 void PrintPreviewHandler::HandlePrintWithCloudPrintDialog(
1067 const base::ListValue* args) {
1068 int page_count = 0;
1069 if (!args || !args->GetInteger(0, &page_count))
1070 return;
1071 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
1072 page_count);
1073
1074 PrintWithCloudPrintDialog();
1075 }
1076
HandleClosePreviewDialog(const base::ListValue *)1077 void PrintPreviewHandler::HandleClosePreviewDialog(
1078 const base::ListValue* /*args*/) {
1079 ReportStats();
1080 ReportUserActionHistogram(CANCEL);
1081
1082 // Record the number of times the user requests to regenerate preview data
1083 // before cancelling.
1084 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1085 regenerate_preview_request_count_);
1086 }
1087
ReportStats()1088 void PrintPreviewHandler::ReportStats() {
1089 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1090 manage_printers_dialog_request_count_);
1091 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1092 manage_cloud_printers_dialog_request_count_);
1093 }
1094
GetNumberFormatAndMeasurementSystem(base::DictionaryValue * settings)1095 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1096 base::DictionaryValue* settings) {
1097
1098 // Getting the measurement system based on the locale.
1099 UErrorCode errorCode = U_ZERO_ERROR;
1100 const char* locale = g_browser_process->GetApplicationLocale().c_str();
1101 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1102 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1103 system = UMS_SI;
1104
1105 // Getting the number formatting based on the locale and writing to
1106 // dictionary.
1107 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1108 settings->SetInteger(kMeasurementSystem, system);
1109 }
1110
HandleGetInitialSettings(const base::ListValue *)1111 void PrintPreviewHandler::HandleGetInitialSettings(
1112 const base::ListValue* /*args*/) {
1113 // Send before SendInitialSettings to allow cloud printer auto select.
1114 SendCloudPrintEnabled();
1115 BrowserThread::PostTaskAndReplyWithResult(
1116 BrowserThread::FILE, FROM_HERE,
1117 base::Bind(&GetDefaultPrinterOnFileThread),
1118 base::Bind(&PrintPreviewHandler::SendInitialSettings,
1119 weak_factory_.GetWeakPtr()));
1120 }
1121
HandleReportUiEvent(const base::ListValue * args)1122 void PrintPreviewHandler::HandleReportUiEvent(const base::ListValue* args) {
1123 int event_group, event_number;
1124 if (!args->GetInteger(0, &event_group) || !args->GetInteger(1, &event_number))
1125 return;
1126
1127 enum UiBucketGroups ui_bucket_group =
1128 static_cast<enum UiBucketGroups>(event_group);
1129 if (ui_bucket_group >= UI_BUCKET_GROUP_BOUNDARY)
1130 return;
1131
1132 switch (ui_bucket_group) {
1133 case DESTINATION_SEARCH: {
1134 enum PrintDestinationBuckets event =
1135 static_cast<enum PrintDestinationBuckets>(event_number);
1136 if (event >= PRINT_DESTINATION_BUCKET_BOUNDARY)
1137 return;
1138 ReportPrintDestinationHistogram(event);
1139 break;
1140 }
1141 case GCP_PROMO: {
1142 enum GcpPromoBuckets event =
1143 static_cast<enum GcpPromoBuckets>(event_number);
1144 if (event >= GCP_PROMO_BUCKET_BOUNDARY)
1145 return;
1146 ReportGcpPromoHistogram(event);
1147 break;
1148 }
1149 default:
1150 break;
1151 }
1152 }
1153
HandleForceOpenNewTab(const base::ListValue * args)1154 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1155 std::string url;
1156 if (!args->GetString(0, &url))
1157 return;
1158 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1159 if (!browser)
1160 return;
1161 chrome::AddSelectedTabWithURL(browser,
1162 GURL(url),
1163 content::PAGE_TRANSITION_LINK);
1164 }
1165
SendInitialSettings(const std::string & default_printer)1166 void PrintPreviewHandler::SendInitialSettings(
1167 const std::string& default_printer) {
1168 PrintPreviewUI* print_preview_ui =
1169 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1170
1171 base::DictionaryValue initial_settings;
1172 initial_settings.SetString(kInitiatorTitle,
1173 print_preview_ui->initiator_title());
1174 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1175 print_preview_ui->source_is_modifiable());
1176 initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1177 initial_settings.SetBoolean(kDocumentHasSelection,
1178 print_preview_ui->source_has_selection());
1179 initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1180 print_preview_ui->print_selection_only());
1181 printing::StickySettings* sticky_settings = GetStickySettings();
1182 sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1183 preview_web_contents()->GetBrowserContext())->GetPrefs());
1184 if (sticky_settings->printer_app_state()) {
1185 initial_settings.SetString(kAppState,
1186 *sticky_settings->printer_app_state());
1187 }
1188
1189 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1190 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1191 cmdline->HasSwitch(switches::kKioskModePrinting));
1192 #if defined(OS_WIN)
1193 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1194 // so will cause the browser to appear hung, so we don't show the link in
1195 // metro.
1196 bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1197 initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1198 #endif
1199
1200 if (print_preview_ui->source_is_modifiable())
1201 GetNumberFormatAndMeasurementSystem(&initial_settings);
1202 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1203 }
1204
ClosePreviewDialog()1205 void PrintPreviewHandler::ClosePreviewDialog() {
1206 PrintPreviewUI* print_preview_ui =
1207 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1208 print_preview_ui->OnClosePrintPreviewDialog();
1209 }
1210
SendAccessToken(const std::string & type,const std::string & access_token)1211 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1212 const std::string& access_token) {
1213 VLOG(1) << "Get getAccessToken finished";
1214 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1215 base::StringValue(type),
1216 base::StringValue(access_token));
1217 }
1218
SendPrinterCapabilities(const base::DictionaryValue * settings_info)1219 void PrintPreviewHandler::SendPrinterCapabilities(
1220 const base::DictionaryValue* settings_info) {
1221 VLOG(1) << "Get printer capabilities finished";
1222 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1223 *settings_info);
1224 }
1225
SendFailedToGetPrinterCapabilities(const std::string & printer_name)1226 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1227 const std::string& printer_name) {
1228 VLOG(1) << "Get printer capabilities failed";
1229 base::StringValue printer_name_value(printer_name);
1230 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1231 printer_name_value);
1232 }
1233
SetupPrinterList(const base::ListValue * printers)1234 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1235 if (!has_logged_printers_count_) {
1236 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1237 has_logged_printers_count_ = true;
1238 }
1239
1240 web_ui()->CallJavascriptFunction("setPrinters", *printers);
1241 }
1242
SendCloudPrintEnabled()1243 void PrintPreviewHandler::SendCloudPrintEnabled() {
1244 Profile* profile = Profile::FromBrowserContext(
1245 preview_web_contents()->GetBrowserContext());
1246 PrefService* prefs = profile->GetPrefs();
1247 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1248 GURL gcp_url(cloud_devices::GetCloudPrintURL());
1249 base::StringValue gcp_url_value(gcp_url.spec());
1250 web_ui()->CallJavascriptFunction("setUseCloudPrint", gcp_url_value);
1251 }
1252 }
1253
SendCloudPrintJob(const base::RefCountedBytes * data)1254 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1255 // BASE64 encode the job data.
1256 std::string raw_data(reinterpret_cast<const char*>(data->front()),
1257 data->size());
1258 std::string base64_data;
1259 base::Base64Encode(raw_data, &base64_data);
1260 base::StringValue data_value(base64_data);
1261
1262 web_ui()->CallJavascriptFunction("printToCloud", data_value);
1263 }
1264
GetInitiator() const1265 WebContents* PrintPreviewHandler::GetInitiator() const {
1266 printing::PrintPreviewDialogController* dialog_controller =
1267 printing::PrintPreviewDialogController::GetInstance();
1268 if (!dialog_controller)
1269 return NULL;
1270 return dialog_controller->GetInitiator(preview_web_contents());
1271 }
1272
OnPrintDialogShown()1273 void PrintPreviewHandler::OnPrintDialogShown() {
1274 ClosePreviewDialog();
1275 }
1276
SelectFile(const base::FilePath & default_filename)1277 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
1278 ui::SelectFileDialog::FileTypeInfo file_type_info;
1279 file_type_info.extensions.resize(1);
1280 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1281
1282 // Initializing |save_path_| if it is not already initialized.
1283 printing::StickySettings* sticky_settings = GetStickySettings();
1284 if (!sticky_settings->save_path()) {
1285 // Allowing IO operation temporarily. It is ok to do so here because
1286 // the select file dialog performs IO anyway in order to display the
1287 // folders and also it is modal.
1288 base::ThreadRestrictions::ScopedAllowIO allow_io;
1289 base::FilePath file_path;
1290 PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1291 sticky_settings->StoreSavePath(file_path);
1292 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1293 preview_web_contents()->GetBrowserContext())->GetPrefs());
1294 }
1295
1296 select_file_dialog_ = ui::SelectFileDialog::Create(
1297 this, new ChromeSelectFilePolicy(preview_web_contents())),
1298 select_file_dialog_->SelectFile(
1299 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1300 base::string16(),
1301 sticky_settings->save_path()->Append(default_filename),
1302 &file_type_info,
1303 0,
1304 base::FilePath::StringType(),
1305 platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1306 NULL);
1307 }
1308
OnPrintPreviewDialogDestroyed()1309 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1310 WebContents* initiator = GetInitiator();
1311 if (!initiator)
1312 return;
1313
1314 printing::PrintViewManager* print_view_manager =
1315 printing::PrintViewManager::FromWebContents(initiator);
1316 print_view_manager->set_observer(NULL);
1317 }
1318
OnPrintPreviewFailed()1319 void PrintPreviewHandler::OnPrintPreviewFailed() {
1320 if (reported_failed_preview_)
1321 return;
1322 reported_failed_preview_ = true;
1323 ReportUserActionHistogram(PREVIEW_FAILED);
1324 }
1325
ShowSystemDialog()1326 void PrintPreviewHandler::ShowSystemDialog() {
1327 HandleShowSystemDialog(NULL);
1328 }
1329
FileSelected(const base::FilePath & path,int index,void * params)1330 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1331 int index, void* params) {
1332 // Updating |save_path_| to the newly selected folder.
1333 printing::StickySettings* sticky_settings = GetStickySettings();
1334 sticky_settings->StoreSavePath(path.DirName());
1335 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1336 preview_web_contents()->GetBrowserContext())->GetPrefs());
1337 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1338 print_to_pdf_path_ = path;
1339 PostPrintToPdfTask();
1340 }
1341
PostPrintToPdfTask()1342 void PrintPreviewHandler::PostPrintToPdfTask() {
1343 scoped_refptr<base::RefCountedBytes> data;
1344 base::string16 title;
1345 if (!GetPreviewDataAndTitle(&data, &title)) {
1346 NOTREACHED() << "Preview data was checked before file dialog.";
1347 return;
1348 }
1349 scoped_ptr<printing::PreviewMetafile> metafile(new printing::PreviewMetafile);
1350 metafile->InitFromData(static_cast<const void*>(data->front()), data->size());
1351 BrowserThread::PostTask(
1352 BrowserThread::FILE, FROM_HERE,
1353 base::Bind(&PrintToPdfCallback, metafile.release(), print_to_pdf_path_));
1354 print_to_pdf_path_ = base::FilePath();
1355 ClosePreviewDialog();
1356 }
1357
FileSelectionCanceled(void * params)1358 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1359 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1360 web_ui()->GetController());
1361 print_preview_ui->OnFileSelectionCancelled();
1362 }
1363
ClearInitiatorDetails()1364 void PrintPreviewHandler::ClearInitiatorDetails() {
1365 WebContents* initiator = GetInitiator();
1366 if (!initiator)
1367 return;
1368
1369 // We no longer require the initiator details. Remove those details associated
1370 // with the preview dialog to allow the initiator to create another preview
1371 // dialog.
1372 printing::PrintPreviewDialogController* dialog_controller =
1373 printing::PrintPreviewDialogController::GetInstance();
1374 if (dialog_controller)
1375 dialog_controller->EraseInitiatorInfo(preview_web_contents());
1376 }
1377
GetPreviewDataAndTitle(scoped_refptr<base::RefCountedBytes> * data,base::string16 * title) const1378 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1379 scoped_refptr<base::RefCountedBytes>* data,
1380 base::string16* title) const {
1381 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1382 web_ui()->GetController());
1383 scoped_refptr<base::RefCountedBytes> tmp_data;
1384 print_preview_ui->GetPrintPreviewDataForIndex(
1385 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1386
1387 if (!tmp_data.get()) {
1388 // Nothing to print, no preview available.
1389 return false;
1390 }
1391 DCHECK(tmp_data->size() && tmp_data->front());
1392
1393 *data = tmp_data;
1394 *title = print_preview_ui->initiator_title();
1395 return true;
1396 }
1397
1398 #if defined(ENABLE_SERVICE_DISCOVERY)
LocalPrinterChanged(bool added,const std::string & name,bool has_local_printing,const local_discovery::DeviceDescription & description)1399 void PrintPreviewHandler::LocalPrinterChanged(
1400 bool added,
1401 const std::string& name,
1402 bool has_local_printing,
1403 const local_discovery::DeviceDescription& description) {
1404 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1405 if (has_local_printing ||
1406 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) {
1407 base::DictionaryValue info;
1408 FillPrinterDescription(name, description, has_local_printing, &info);
1409 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1410 }
1411 }
1412
LocalPrinterRemoved(const std::string & name)1413 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1414 }
1415
LocalPrinterCacheFlushed()1416 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1417 }
1418
PrivetCapabilitiesUpdateClient(scoped_ptr<local_discovery::PrivetHTTPClient> http_client)1419 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1420 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1421 if (!PrivetUpdateClient(http_client.Pass()))
1422 return;
1423
1424 privet_capabilities_operation_ =
1425 privet_http_client_->CreateCapabilitiesOperation(
1426 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1427 base::Unretained(this)));
1428 privet_capabilities_operation_->Start();
1429 }
1430
PrivetUpdateClient(scoped_ptr<local_discovery::PrivetHTTPClient> http_client)1431 bool PrintPreviewHandler::PrivetUpdateClient(
1432 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1433 if (!http_client) {
1434 SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1435 privet_http_resolution_.reset();
1436 return false;
1437 }
1438
1439 privet_local_print_operation_.reset();
1440 privet_capabilities_operation_.reset();
1441 privet_http_client_ =
1442 local_discovery::PrivetV1HTTPClient::CreateDefault(http_client.Pass());
1443
1444 privet_http_resolution_.reset();
1445
1446 return true;
1447 }
1448
PrivetLocalPrintUpdateClient(std::string print_ticket,std::string capabilities,gfx::Size page_size,scoped_ptr<local_discovery::PrivetHTTPClient> http_client)1449 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1450 std::string print_ticket,
1451 std::string capabilities,
1452 gfx::Size page_size,
1453 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1454 if (!PrivetUpdateClient(http_client.Pass()))
1455 return;
1456
1457 StartPrivetLocalPrint(print_ticket, capabilities, page_size);
1458 }
1459
StartPrivetLocalPrint(const std::string & print_ticket,const std::string & capabilities,const gfx::Size & page_size)1460 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string& print_ticket,
1461 const std::string& capabilities,
1462 const gfx::Size& page_size) {
1463 privet_local_print_operation_ =
1464 privet_http_client_->CreateLocalPrintOperation(this);
1465
1466 privet_local_print_operation_->SetTicket(print_ticket);
1467 privet_local_print_operation_->SetCapabilities(capabilities);
1468
1469 scoped_refptr<base::RefCountedBytes> data;
1470 base::string16 title;
1471
1472 if (!GetPreviewDataAndTitle(&data, &title)) {
1473 base::FundamentalValue http_code_value(-1);
1474 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1475 return;
1476 }
1477
1478 privet_local_print_operation_->SetJobname(base::UTF16ToUTF8(title));
1479 privet_local_print_operation_->SetPageSize(page_size);
1480 privet_local_print_operation_->SetData(data);
1481
1482 Profile* profile = Profile::FromWebUI(web_ui());
1483 SigninManagerBase* signin_manager =
1484 SigninManagerFactory::GetForProfileIfExists(profile);
1485
1486 if (signin_manager) {
1487 privet_local_print_operation_->SetUsername(
1488 signin_manager->GetAuthenticatedUsername());
1489 }
1490
1491 privet_local_print_operation_->Start();
1492 }
1493
1494
OnPrivetCapabilities(const base::DictionaryValue * capabilities)1495 void PrintPreviewHandler::OnPrivetCapabilities(
1496 const base::DictionaryValue* capabilities) {
1497 std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1498
1499 if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError)) {
1500 SendPrivetCapabilitiesError(name);
1501 return;
1502 }
1503
1504 base::DictionaryValue printer_info;
1505 const local_discovery::DeviceDescription* description =
1506 printer_lister_->GetDeviceDescription(name);
1507
1508 if (!description) {
1509 SendPrivetCapabilitiesError(name);
1510 return;
1511 }
1512
1513 FillPrinterDescription(name, *description, true, &printer_info);
1514
1515 web_ui()->CallJavascriptFunction(
1516 "onPrivetCapabilitiesSet",
1517 printer_info,
1518 *capabilities);
1519
1520 privet_capabilities_operation_.reset();
1521 }
1522
SendPrivetCapabilitiesError(const std::string & device_name)1523 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1524 const std::string& device_name) {
1525 base::StringValue name_value(device_name);
1526 web_ui()->CallJavascriptFunction(
1527 "failedToGetPrivetPrinterCapabilities",
1528 name_value);
1529 }
1530
PrintToPrivetPrinter(const std::string & device_name,const std::string & ticket,const std::string & capabilities,const gfx::Size & page_size)1531 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string& device_name,
1532 const std::string& ticket,
1533 const std::string& capabilities,
1534 const gfx::Size& page_size) {
1535 CreatePrivetHTTP(
1536 device_name,
1537 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1538 base::Unretained(this),
1539 ticket,
1540 capabilities,
1541 page_size));
1542 }
1543
CreatePrivetHTTP(const std::string & name,const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback & callback)1544 bool PrintPreviewHandler::CreatePrivetHTTP(
1545 const std::string& name,
1546 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1547 callback) {
1548 const local_discovery::DeviceDescription* device_description =
1549 printer_lister_->GetDeviceDescription(name);
1550
1551 if (!device_description) {
1552 SendPrivetCapabilitiesError(name);
1553 return false;
1554 }
1555
1556 privet_http_factory_ =
1557 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1558 service_discovery_client_,
1559 Profile::FromWebUI(web_ui())->GetRequestContext());
1560 privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
1561 name, device_description->address, callback);
1562 privet_http_resolution_->Start();
1563
1564 return true;
1565 }
1566
OnPrivetPrintingDone(const local_discovery::PrivetLocalPrintOperation * print_operation)1567 void PrintPreviewHandler::OnPrivetPrintingDone(
1568 const local_discovery::PrivetLocalPrintOperation* print_operation) {
1569 ClosePreviewDialog();
1570 }
1571
OnPrivetPrintingError(const local_discovery::PrivetLocalPrintOperation * print_operation,int http_code)1572 void PrintPreviewHandler::OnPrivetPrintingError(
1573 const local_discovery::PrivetLocalPrintOperation* print_operation,
1574 int http_code) {
1575 base::FundamentalValue http_code_value(http_code);
1576 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1577 }
1578
FillPrinterDescription(const std::string & name,const local_discovery::DeviceDescription & description,bool has_local_printing,base::DictionaryValue * printer_value)1579 void PrintPreviewHandler::FillPrinterDescription(
1580 const std::string& name,
1581 const local_discovery::DeviceDescription& description,
1582 bool has_local_printing,
1583 base::DictionaryValue* printer_value) {
1584 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1585
1586 printer_value->SetString("serviceName", name);
1587 printer_value->SetString("name", description.name);
1588 printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1589 printer_value->SetBoolean(
1590 "isUnregistered",
1591 description.id.empty() &&
1592 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos));
1593 printer_value->SetString("cloudID", description.id);
1594 }
1595
1596 #endif // defined(ENABLE_SERVICE_DISCOVERY)
1597