Extract code handling PrinterProviderAPI from PrintPreviewHandler
[chromium-blink-merge.git] / chrome / browser / ui / webui / print_preview / print_preview_handler.cc
blobe691d89e1acd5cf7714fd57f924fe7e501d12d1b
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/webui/print_preview/print_preview_handler.h"
7 #include <ctype.h>
9 #include <map>
10 #include <string>
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/app_mode/app_mode_utils.h"
31 #include "chrome/browser/browser_process.h"
32 #include "chrome/browser/platform_util.h"
33 #include "chrome/browser/printing/print_dialog_cloud.h"
34 #include "chrome/browser/printing/print_error_dialog.h"
35 #include "chrome/browser/printing/print_job_manager.h"
36 #include "chrome/browser/printing/print_preview_dialog_controller.h"
37 #include "chrome/browser/printing/print_view_manager.h"
38 #include "chrome/browser/printing/printer_manager_dialog.h"
39 #include "chrome/browser/profiles/profile.h"
40 #include "chrome/browser/signin/account_reconcilor_factory.h"
41 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
42 #include "chrome/browser/signin/signin_manager_factory.h"
43 #include "chrome/browser/ui/browser_finder.h"
44 #include "chrome/browser/ui/browser_tabstrip.h"
45 #include "chrome/browser/ui/chrome_select_file_policy.h"
46 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
47 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
48 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
49 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
50 #include "chrome/common/chrome_paths.h"
51 #include "chrome/common/chrome_switches.h"
52 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
53 #include "chrome/common/cloud_print/cloud_print_constants.h"
54 #include "chrome/common/crash_keys.h"
55 #include "chrome/common/pref_names.h"
56 #include "components/cloud_devices/common/cloud_device_description.h"
57 #include "components/cloud_devices/common/cloud_devices_urls.h"
58 #include "components/cloud_devices/common/printer_description.h"
59 #include "components/printing/common/print_messages.h"
60 #include "components/signin/core/browser/account_reconcilor.h"
61 #include "components/signin/core/browser/profile_oauth2_token_service.h"
62 #include "components/signin/core/browser/signin_manager.h"
63 #include "components/signin/core/common/profile_management_switches.h"
64 #include "content/public/browser/browser_context.h"
65 #include "content/public/browser/browser_thread.h"
66 #include "content/public/browser/navigation_controller.h"
67 #include "content/public/browser/navigation_entry.h"
68 #include "content/public/browser/render_process_host.h"
69 #include "content/public/browser/render_view_host.h"
70 #include "content/public/browser/web_contents.h"
71 #include "content/public/browser/web_ui.h"
72 #include "google_apis/gaia/oauth2_token_service.h"
73 #include "net/base/url_util.h"
74 #include "printing/backend/print_backend.h"
75 #include "printing/backend/print_backend_consts.h"
76 #include "printing/metafile.h"
77 #include "printing/pdf_metafile_skia.h"
78 #include "printing/pdf_render_settings.h"
79 #include "printing/print_settings.h"
80 #include "printing/printing_context.h"
81 #include "printing/units.h"
82 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
84 #if defined(OS_CHROMEOS)
85 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
86 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
87 #endif
89 #if defined(ENABLE_SERVICE_DISCOVERY)
90 #include "chrome/browser/local_discovery/privet_constants.h"
91 #endif
93 using content::BrowserThread;
94 using content::RenderViewHost;
95 using content::WebContents;
97 namespace {
99 enum UserActionBuckets {
100 PRINT_TO_PRINTER,
101 PRINT_TO_PDF,
102 CANCEL,
103 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
104 PREVIEW_FAILED,
105 PREVIEW_STARTED,
106 INITIATOR_CRASHED, // UNUSED
107 INITIATOR_CLOSED,
108 PRINT_WITH_CLOUD_PRINT,
109 PRINT_WITH_PRIVET,
110 USERACTION_BUCKET_BOUNDARY
113 enum PrintSettingsBuckets {
114 LANDSCAPE = 0,
115 PORTRAIT,
116 COLOR,
117 BLACK_AND_WHITE,
118 COLLATE,
119 SIMPLEX,
120 DUPLEX,
121 TOTAL,
122 HEADERS_AND_FOOTERS,
123 CSS_BACKGROUND,
124 SELECTION_ONLY,
125 EXTERNAL_PDF_PREVIEW,
126 PAGE_RANGE,
127 DEFAULT_MEDIA,
128 NON_DEFAULT_MEDIA,
129 COPIES,
130 NON_DEFAULT_MARGINS,
131 PRINT_SETTINGS_BUCKET_BOUNDARY
134 void ReportUserActionHistogram(enum UserActionBuckets event) {
135 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
136 USERACTION_BUCKET_BOUNDARY);
139 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
140 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
141 PRINT_SETTINGS_BUCKET_BOUNDARY);
144 // Name of a dictionary field holding cloud print related data;
145 const char kAppState[] = "appState";
146 // Name of a dictionary field holding the initiator title.
147 const char kInitiatorTitle[] = "initiatorTitle";
148 // Name of a dictionary field holding the measurement system according to the
149 // locale.
150 const char kMeasurementSystem[] = "measurementSystem";
151 // Name of a dictionary field holding the number format according to the locale.
152 const char kNumberFormat[] = "numberFormat";
153 // Name of a dictionary field specifying whether to print automatically in
154 // kiosk mode. See http://crbug.com/31395.
155 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
156 // Dictionary field to indicate whether Chrome is running in forced app (app
157 // kiosk) mode. It's not the same as desktop Chrome kiosk (the one above).
158 const char kAppKioskMode[] = "appKioskMode";
159 // Dictionary field to store Cloud Print base URL.
160 const char kCloudPrintUrl[] = "cloudPrintUrl";
161 #if defined(OS_WIN)
162 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
163 #endif
164 // Name of a dictionary field holding the state of selection for document.
165 const char kDocumentHasSelection[] = "documentHasSelection";
167 // Id of the predefined PDF printer.
168 const char kLocalPdfPrinterId[] = "Save as PDF";
170 // Additional printer capability setting keys.
171 const char kPrinterId[] = "printerId";
172 const char kPrinterCapabilities[] = "capabilities";
174 // Get the print job settings dictionary from |args|. The caller takes
175 // ownership of the returned DictionaryValue. Returns NULL on failure.
176 base::DictionaryValue* GetSettingsDictionary(const base::ListValue* args) {
177 std::string json_str;
178 if (!args->GetString(0, &json_str)) {
179 NOTREACHED() << "Could not read JSON argument";
180 return NULL;
182 if (json_str.empty()) {
183 NOTREACHED() << "Empty print job settings";
184 return NULL;
186 scoped_ptr<base::DictionaryValue> settings(
187 static_cast<base::DictionaryValue*>(
188 base::JSONReader::Read(json_str)));
189 if (!settings.get() || !settings->IsType(base::Value::TYPE_DICTIONARY)) {
190 NOTREACHED() << "Print job settings must be a dictionary.";
191 return NULL;
194 if (settings->empty()) {
195 NOTREACHED() << "Print job settings dictionary is empty";
196 return NULL;
199 return settings.release();
202 // Track the popularity of print settings and report the stats.
203 void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
204 ReportPrintSettingHistogram(TOTAL);
206 const base::ListValue* page_range_array = NULL;
207 if (settings.GetList(printing::kSettingPageRange, &page_range_array) &&
208 !page_range_array->empty()) {
209 ReportPrintSettingHistogram(PAGE_RANGE);
212 const base::DictionaryValue* media_size_value = NULL;
213 if (settings.GetDictionary(printing::kSettingMediaSize, &media_size_value) &&
214 !media_size_value->empty()) {
215 bool is_default = false;
216 if (media_size_value->GetBoolean(printing::kSettingMediaSizeIsDefault,
217 &is_default) &&
218 is_default) {
219 ReportPrintSettingHistogram(DEFAULT_MEDIA);
220 } else {
221 ReportPrintSettingHistogram(NON_DEFAULT_MEDIA);
225 bool landscape = false;
226 if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
227 ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
229 int copies = 1;
230 if (settings.GetInteger(printing::kSettingCopies, &copies) && copies > 1)
231 ReportPrintSettingHistogram(COPIES);
233 bool collate = false;
234 if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
235 ReportPrintSettingHistogram(COLLATE);
237 int duplex_mode = 0;
238 if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
239 ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
241 int color_mode = 0;
242 if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
243 ReportPrintSettingHistogram(
244 printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
247 int margins_type = 0;
248 if (settings.GetInteger(printing::kSettingMarginsType, &margins_type) &&
249 margins_type != 0) {
250 ReportPrintSettingHistogram(NON_DEFAULT_MARGINS);
253 bool headers = false;
254 if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
255 headers) {
256 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
259 bool css_background = false;
260 if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
261 &css_background) && css_background) {
262 ReportPrintSettingHistogram(CSS_BACKGROUND);
265 bool selection_only = false;
266 if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
267 &selection_only) && selection_only) {
268 ReportPrintSettingHistogram(SELECTION_ONLY);
271 bool external_preview = false;
272 if (settings.GetBoolean(printing::kSettingOpenPDFInPreview,
273 &external_preview) && external_preview) {
274 ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW);
278 // Callback that stores a PDF file on disk.
279 void PrintToPdfCallback(const scoped_refptr<base::RefCountedBytes>& data,
280 const base::FilePath& path,
281 const base::Closure& pdf_file_saved_closure) {
282 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
283 printing::PdfMetafileSkia metafile;
284 metafile.InitFromData(static_cast<const void*>(data->front()), data->size());
285 base::File file(path,
286 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
287 metafile.SaveTo(&file);
288 if (!pdf_file_saved_closure.is_null())
289 pdf_file_saved_closure.Run();
292 std::string GetDefaultPrinterOnFileThread() {
293 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
295 scoped_refptr<printing::PrintBackend> print_backend(
296 printing::PrintBackend::CreateInstance(NULL));
298 std::string default_printer = print_backend->GetDefaultPrinterName();
299 VLOG(1) << "Default Printer: " << default_printer;
300 return default_printer;
303 class PrintingContextDelegate : public printing::PrintingContext::Delegate {
304 public:
305 // PrintingContext::Delegate methods.
306 gfx::NativeView GetParentView() override { return NULL; }
307 std::string GetAppLocale() override {
308 return g_browser_process->GetApplicationLocale();
312 gfx::Size GetDefaultPdfMediaSizeMicrons() {
313 PrintingContextDelegate delegate;
314 scoped_ptr<printing::PrintingContext> printing_context(
315 printing::PrintingContext::Create(&delegate));
316 if (printing::PrintingContext::OK != printing_context->UsePdfSettings() ||
317 printing_context->settings().device_units_per_inch() <= 0) {
318 return gfx::Size();
320 gfx::Size pdf_media_size = printing_context->GetPdfPaperSizeDeviceUnits();
321 float deviceMicronsPerDeviceUnit =
322 (printing::kHundrethsMMPerInch * 10.0f) /
323 printing_context->settings().device_units_per_inch();
324 return gfx::Size(pdf_media_size.width() * deviceMicronsPerDeviceUnit,
325 pdf_media_size.height() * deviceMicronsPerDeviceUnit);
328 typedef base::Callback<void(const base::DictionaryValue*)>
329 GetPdfCapabilitiesCallback;
331 scoped_ptr<base::DictionaryValue> GetPdfCapabilitiesOnFileThread(
332 const std::string& locale) {
333 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
335 cloud_devices::CloudDeviceDescription description;
336 using namespace cloud_devices::printer;
338 OrientationCapability orientation;
339 orientation.AddOption(cloud_devices::printer::PORTRAIT);
340 orientation.AddOption(cloud_devices::printer::LANDSCAPE);
341 orientation.AddDefaultOption(AUTO_ORIENTATION, true);
342 orientation.SaveTo(&description);
344 ColorCapability color;
346 Color standard_color(STANDARD_COLOR);
347 standard_color.vendor_id = base::IntToString(printing::COLOR);
348 color.AddDefaultOption(standard_color, true);
350 color.SaveTo(&description);
352 static const cloud_devices::printer::MediaType kPdfMedia[] = {
353 ISO_A4,
354 ISO_A3,
355 NA_LETTER,
356 NA_LEGAL,
357 NA_LEDGER
359 const gfx::Size default_media_size = GetDefaultPdfMediaSizeMicrons();
360 Media default_media(
361 "", "", default_media_size.width(), default_media_size.height());
362 if (!default_media.MatchBySize() ||
363 std::find(kPdfMedia,
364 kPdfMedia + arraysize(kPdfMedia),
365 default_media.type) == kPdfMedia + arraysize(kPdfMedia)) {
366 default_media = Media(locale == "en-US" ? NA_LETTER : ISO_A4);
368 MediaCapability media;
369 for (size_t i = 0; i < arraysize(kPdfMedia); ++i) {
370 Media media_option(kPdfMedia[i]);
371 media.AddDefaultOption(media_option,
372 default_media.type == media_option.type);
374 media.SaveTo(&description);
376 return scoped_ptr<base::DictionaryValue>(description.root().DeepCopy());
379 scoped_ptr<base::DictionaryValue> GetLocalPrinterCapabilitiesOnFileThread(
380 const std::string& printer_name) {
381 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
383 scoped_refptr<printing::PrintBackend> print_backend(
384 printing::PrintBackend::CreateInstance(NULL));
386 VLOG(1) << "Get printer capabilities start for " << printer_name;
387 crash_keys::ScopedPrinterInfo crash_key(
388 print_backend->GetPrinterDriverInfo(printer_name));
390 if (!print_backend->IsValidPrinter(printer_name)) {
391 LOG(WARNING) << "Invalid printer " << printer_name;
392 return scoped_ptr<base::DictionaryValue>();
395 printing::PrinterSemanticCapsAndDefaults info;
396 if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
397 LOG(WARNING) << "Failed to get capabilities for " << printer_name;
398 return scoped_ptr<base::DictionaryValue>();
401 scoped_ptr<base::DictionaryValue> description(
402 cloud_print::PrinterSemanticCapsAndDefaultsToCdd(info));
403 if (!description) {
404 LOG(WARNING) << "Failed to convert capabilities for " << printer_name;
405 return scoped_ptr<base::DictionaryValue>();
408 return description.Pass();
411 void EnumeratePrintersOnFileThread(base::ListValue* printers) {
412 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
414 scoped_refptr<printing::PrintBackend> print_backend(
415 printing::PrintBackend::CreateInstance(NULL));
417 VLOG(1) << "Enumerate printers start";
418 printing::PrinterList printer_list;
419 print_backend->EnumeratePrinters(&printer_list);
421 for (printing::PrinterList::iterator it = printer_list.begin();
422 it != printer_list.end(); ++it) {
423 base::DictionaryValue* printer_info = new base::DictionaryValue;
424 printers->Append(printer_info);
425 std::string printer_name;
426 std::string printer_description;
427 #if defined(OS_MACOSX)
428 // On Mac, |it->printer_description| specifies the printer name and
429 // |it->printer_name| specifies the device name / printer queue name.
430 printer_name = it->printer_description;
431 if (!it->options[kDriverNameTagName].empty())
432 printer_description = it->options[kDriverNameTagName];
433 #else
434 printer_name = it->printer_name;
435 printer_description = it->printer_description;
436 #endif
437 printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
438 printer_info->SetString(printing::kSettingPrinterDescription,
439 printer_description);
440 printer_info->SetString(printing::kSettingPrinterName, printer_name);
441 VLOG(1) << "Found printer " << printer_name
442 << " with device name " << it->printer_name;
444 base::DictionaryValue* options = new base::DictionaryValue;
445 printer_info->Set(printing::kSettingPrinterOptions, options);
446 for (std::map<std::string, std::string>::iterator opt = it->options.begin();
447 opt != it->options.end();
448 ++opt) {
449 options->SetString(opt->first, opt->second);
452 VLOG(1) << "Found printer " << printer_name << " with device name "
453 << it->printer_name;
455 VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
456 << " printers";
459 typedef base::Callback<void(const base::DictionaryValue*)>
460 GetPrinterCapabilitiesSuccessCallback;
461 typedef base::Callback<void(const std::string&)>
462 GetPrinterCapabilitiesFailureCallback;
464 void GetPrinterCapabilitiesOnFileThread(
465 const std::string& printer_name,
466 const std::string& locale,
467 const GetPrinterCapabilitiesSuccessCallback& success_cb,
468 const GetPrinterCapabilitiesFailureCallback& failure_cb) {
469 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
470 DCHECK(!printer_name.empty());
472 scoped_ptr<base::DictionaryValue> printer_capabilities(
473 printer_name == kLocalPdfPrinterId ?
474 GetPdfCapabilitiesOnFileThread(locale) :
475 GetLocalPrinterCapabilitiesOnFileThread(printer_name));
476 if (!printer_capabilities) {
477 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
478 base::Bind(failure_cb, printer_name));
479 return;
482 scoped_ptr<base::DictionaryValue> printer_info(new base::DictionaryValue);
483 printer_info->SetString(kPrinterId, printer_name);
484 printer_info->Set(kPrinterCapabilities, printer_capabilities.release());
486 BrowserThread::PostTask(
487 BrowserThread::UI, FROM_HERE,
488 base::Bind(success_cb, base::Owned(printer_info.release())));
491 base::LazyInstance<printing::StickySettings> g_sticky_settings =
492 LAZY_INSTANCE_INITIALIZER;
494 printing::StickySettings* GetStickySettings() {
495 return g_sticky_settings.Pointer();
498 } // namespace
500 class PrintPreviewHandler::AccessTokenService
501 : public OAuth2TokenService::Consumer {
502 public:
503 explicit AccessTokenService(PrintPreviewHandler* handler)
504 : OAuth2TokenService::Consumer("print_preview"),
505 handler_(handler) {
508 void RequestToken(const std::string& type) {
509 if (requests_.find(type) != requests_.end())
510 return; // Already in progress.
512 OAuth2TokenService* service = NULL;
513 std::string account_id;
514 if (type == "profile") {
515 Profile* profile = Profile::FromWebUI(handler_->web_ui());
516 if (profile) {
517 ProfileOAuth2TokenService* token_service =
518 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
519 SigninManagerBase* signin_manager =
520 SigninManagerFactory::GetInstance()->GetForProfile(profile);
521 account_id = signin_manager->GetAuthenticatedAccountId();
522 service = token_service;
524 } else if (type == "device") {
525 #if defined(OS_CHROMEOS)
526 chromeos::DeviceOAuth2TokenService* token_service =
527 chromeos::DeviceOAuth2TokenServiceFactory::Get();
528 account_id = token_service->GetRobotAccountId();
529 service = token_service;
530 #endif
533 if (service) {
534 OAuth2TokenService::ScopeSet oauth_scopes;
535 oauth_scopes.insert(cloud_devices::kCloudPrintAuthScope);
536 scoped_ptr<OAuth2TokenService::Request> request(
537 service->StartRequest(account_id, oauth_scopes, this));
538 requests_[type].reset(request.release());
539 } else {
540 handler_->SendAccessToken(type, std::string()); // Unknown type.
544 void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
545 const std::string& access_token,
546 const base::Time& expiration_time) override {
547 OnServiceResponce(request, access_token);
550 void OnGetTokenFailure(const OAuth2TokenService::Request* request,
551 const GoogleServiceAuthError& error) override {
552 OnServiceResponce(request, std::string());
555 private:
556 void OnServiceResponce(const OAuth2TokenService::Request* request,
557 const std::string& access_token) {
558 for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
559 if (i->second == request) {
560 handler_->SendAccessToken(i->first, access_token);
561 requests_.erase(i);
562 return;
565 NOTREACHED();
568 typedef std::map<std::string,
569 linked_ptr<OAuth2TokenService::Request> > Requests;
570 Requests requests_;
571 PrintPreviewHandler* handler_;
573 DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
576 PrintPreviewHandler::PrintPreviewHandler()
577 : regenerate_preview_request_count_(0),
578 manage_printers_dialog_request_count_(0),
579 manage_cloud_printers_dialog_request_count_(0),
580 reported_failed_preview_(false),
581 has_logged_printers_count_(false),
582 reconcilor_(NULL),
583 weak_factory_(this) {
584 ReportUserActionHistogram(PREVIEW_STARTED);
587 PrintPreviewHandler::~PrintPreviewHandler() {
588 if (select_file_dialog_.get())
589 select_file_dialog_->ListenerDestroyed();
591 UnregisterForMergeSession();
594 void PrintPreviewHandler::RegisterMessages() {
595 web_ui()->RegisterMessageCallback("getPrinters",
596 base::Bind(&PrintPreviewHandler::HandleGetPrinters,
597 base::Unretained(this)));
598 web_ui()->RegisterMessageCallback("getPreview",
599 base::Bind(&PrintPreviewHandler::HandleGetPreview,
600 base::Unretained(this)));
601 web_ui()->RegisterMessageCallback("print",
602 base::Bind(&PrintPreviewHandler::HandlePrint,
603 base::Unretained(this)));
604 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
605 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
606 base::Unretained(this)));
607 #if defined(ENABLE_BASIC_PRINTING)
608 web_ui()->RegisterMessageCallback("showSystemDialog",
609 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
610 base::Unretained(this)));
611 #endif // ENABLE_BASIC_PRINTING
612 web_ui()->RegisterMessageCallback("signIn",
613 base::Bind(&PrintPreviewHandler::HandleSignin,
614 base::Unretained(this)));
615 web_ui()->RegisterMessageCallback("getAccessToken",
616 base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
617 base::Unretained(this)));
618 web_ui()->RegisterMessageCallback("manageCloudPrinters",
619 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
620 base::Unretained(this)));
621 web_ui()->RegisterMessageCallback("manageLocalPrinters",
622 base::Bind(&PrintPreviewHandler::HandleManagePrinters,
623 base::Unretained(this)));
624 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
625 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
626 base::Unretained(this)));
627 web_ui()->RegisterMessageCallback("hidePreview",
628 base::Bind(&PrintPreviewHandler::HandleHidePreview,
629 base::Unretained(this)));
630 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
631 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
632 base::Unretained(this)));
633 web_ui()->RegisterMessageCallback("saveAppState",
634 base::Bind(&PrintPreviewHandler::HandleSaveAppState,
635 base::Unretained(this)));
636 web_ui()->RegisterMessageCallback("getInitialSettings",
637 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
638 base::Unretained(this)));
639 web_ui()->RegisterMessageCallback("forceOpenNewTab",
640 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
641 base::Unretained(this)));
642 web_ui()->RegisterMessageCallback("getPrivetPrinters",
643 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
644 base::Unretained(this)));
645 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
646 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
647 base::Unretained(this)));
648 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
649 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
650 base::Unretained(this)));
651 web_ui()->RegisterMessageCallback(
652 "getExtensionPrinters",
653 base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinters,
654 base::Unretained(this)));
655 web_ui()->RegisterMessageCallback(
656 "getExtensionPrinterCapabilities",
657 base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinterCapabilities,
658 base::Unretained(this)));
659 RegisterForMergeSession();
662 bool PrintPreviewHandler::PrivetPrintingEnabled() {
663 #if defined(ENABLE_SERVICE_DISCOVERY)
664 return true;
665 #else
666 return false;
667 #endif
670 WebContents* PrintPreviewHandler::preview_web_contents() const {
671 return web_ui()->GetWebContents();
674 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
675 base::ListValue* results = new base::ListValue;
676 BrowserThread::PostTaskAndReply(
677 BrowserThread::FILE, FROM_HERE,
678 base::Bind(&EnumeratePrintersOnFileThread,
679 base::Unretained(results)),
680 base::Bind(&PrintPreviewHandler::SetupPrinterList,
681 weak_factory_.GetWeakPtr(),
682 base::Owned(results)));
685 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
686 if (!PrivetPrintingEnabled())
687 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
688 #if defined(ENABLE_SERVICE_DISCOVERY)
689 local_discovery::ServiceDiscoverySharedClient::GetInstanceWithoutAlert(
690 base::Bind(&PrintPreviewHandler::StartPrivetLister,
691 weak_factory_.GetWeakPtr()));
692 #endif // ENABLE_SERVICE_DISCOVERY
695 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
696 const base::ListValue* args) {
697 #if defined(ENABLE_SERVICE_DISCOVERY)
698 if (PrivetPrintingEnabled() && printer_lister_) {
699 printer_lister_->Stop();
701 #endif
704 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
705 const base::ListValue* args) {
706 #if defined(ENABLE_SERVICE_DISCOVERY)
707 std::string name;
708 bool success = args->GetString(0, &name);
709 DCHECK(success);
711 CreatePrivetHTTP(
712 name,
713 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
714 base::Unretained(this)));
715 #endif
718 void PrintPreviewHandler::HandleGetExtensionPrinters(
719 const base::ListValue* args) {
720 EnsureExtensionPrinterHandlerSet();
721 // Make sure all in progress requests are canceled before new printer search
722 // starts.
723 extension_printer_handler_->Reset();
724 extension_printer_handler_->StartGetPrinters(base::Bind(
725 &PrintPreviewHandler::OnGotPrintersForExtension, base::Unretained(this)));
728 void PrintPreviewHandler::HandleGetExtensionPrinterCapabilities(
729 const base::ListValue* args) {
730 std::string printer_id;
731 bool ok = args->GetString(0, &printer_id);
732 DCHECK(ok);
734 EnsureExtensionPrinterHandlerSet();
735 extension_printer_handler_->StartGetCapability(
736 printer_id,
737 base::Bind(&PrintPreviewHandler::OnGotExtensionPrinterCapabilities,
738 base::Unretained(this)));
741 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
742 DCHECK_EQ(3U, args->GetSize());
743 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
744 if (!settings.get())
745 return;
746 int request_id = -1;
747 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
748 return;
750 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
751 web_ui()->GetController());
752 print_preview_ui->OnPrintPreviewRequest(request_id);
753 // Add an additional key in order to identify |print_preview_ui| later on
754 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
755 // thread.
756 settings->SetInteger(printing::kPreviewUIID,
757 print_preview_ui->GetIDForPrintPreviewUI());
759 // Increment request count.
760 ++regenerate_preview_request_count_;
762 WebContents* initiator = GetInitiator();
763 if (!initiator) {
764 ReportUserActionHistogram(INITIATOR_CLOSED);
765 print_preview_ui->OnClosePrintPreviewDialog();
766 return;
769 // Retrieve the page title and url and send it to the renderer process if
770 // headers and footers are to be displayed.
771 bool display_header_footer = false;
772 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
773 &display_header_footer)) {
774 NOTREACHED();
776 if (display_header_footer) {
777 settings->SetString(printing::kSettingHeaderFooterTitle,
778 initiator->GetTitle());
779 std::string url;
780 content::NavigationEntry* entry =
781 initiator->GetController().GetLastCommittedEntry();
782 if (entry)
783 url = entry->GetVirtualURL().spec();
784 settings->SetString(printing::kSettingHeaderFooterURL, url);
787 bool generate_draft_data = false;
788 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
789 &generate_draft_data);
790 DCHECK(success);
792 if (!generate_draft_data) {
793 double draft_page_count_double = -1;
794 success = args->GetDouble(1, &draft_page_count_double);
795 DCHECK(success);
796 int draft_page_count = static_cast<int>(draft_page_count_double);
798 bool preview_modifiable = false;
799 success = args->GetBoolean(2, &preview_modifiable);
800 DCHECK(success);
802 if (draft_page_count != -1 && preview_modifiable &&
803 print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
804 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
808 VLOG(1) << "Print preview request start";
809 RenderViewHost* rvh = initiator->GetRenderViewHost();
810 rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
813 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
814 ReportStats();
816 // Record the number of times the user requests to regenerate preview data
817 // before printing.
818 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
819 regenerate_preview_request_count_);
821 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
822 if (!settings.get())
823 return;
825 ReportPrintSettingsStats(*settings);
827 // Never try to add headers/footers here. It's already in the generated PDF.
828 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
830 bool print_to_pdf = false;
831 bool is_cloud_printer = false;
832 bool print_with_privet = false;
833 bool print_with_extension = false;
835 bool open_pdf_in_preview = false;
836 #if defined(OS_MACOSX)
837 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
838 #endif
840 if (!open_pdf_in_preview) {
841 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
842 settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
843 settings->GetBoolean(printing::kSettingPrintWithExtension,
844 &print_with_extension);
845 is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
848 int page_count = 0;
849 settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
851 if (print_to_pdf) {
852 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
853 ReportUserActionHistogram(PRINT_TO_PDF);
854 PrintToPdf();
855 return;
858 #if defined(ENABLE_SERVICE_DISCOVERY)
859 if (print_with_privet && PrivetPrintingEnabled()) {
860 std::string printer_name;
861 std::string print_ticket;
862 std::string capabilities;
863 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
864 ReportUserActionHistogram(PRINT_WITH_PRIVET);
866 int width = 0;
867 int height = 0;
868 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
869 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
870 !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
871 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
872 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
873 width <= 0 || height <= 0) {
874 NOTREACHED();
875 base::FundamentalValue http_code_value(-1);
876 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
877 return;
880 PrintToPrivetPrinter(
881 printer_name, print_ticket, capabilities, gfx::Size(width, height));
882 return;
884 #endif
886 if (print_with_extension) {
887 // TODO(tbarzic): Record UMA stats.
889 base::string16 title;
890 scoped_refptr<base::RefCountedBytes> data;
891 if (!GetPreviewDataAndTitle(&data, &title)) {
892 LOG(ERROR) << "Nothing to print; no preview available.";
893 OnExtensionPrintResult(false, "NO_DATA");
894 return;
897 EnsureExtensionPrinterHandlerSet();
898 extension_printer_handler_->StartPrint(
899 *settings, data,
900 base::Bind(&PrintPreviewHandler::OnExtensionPrintResult,
901 base::Unretained(this)));
902 return;
905 scoped_refptr<base::RefCountedBytes> data;
906 base::string16 title;
907 if (!GetPreviewDataAndTitle(&data, &title)) {
908 // Nothing to print, no preview available.
909 return;
912 if (is_cloud_printer) {
913 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
914 page_count);
915 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
916 SendCloudPrintJob(data.get());
917 } else {
918 bool system_dialog = false;
919 settings->GetBoolean(printing::kSettingShowSystemDialog, &system_dialog);
920 if (system_dialog) {
921 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count);
922 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
923 } else {
924 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
925 ReportUserActionHistogram(PRINT_TO_PRINTER);
928 // This tries to activate the initiator as well, so do not clear the
929 // association with the initiator yet.
930 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
931 web_ui()->GetController());
932 print_preview_ui->OnHidePreviewDialog();
934 // Do this so the initiator can open a new print preview dialog, while the
935 // current print preview dialog is still handling its print job.
936 WebContents* initiator = GetInitiator();
937 if (initiator) {
938 // Save initiator IDs. |PrintingMessageFilter::OnUpdatePrintSettings|
939 // would be called when initiator info is cleared.
940 settings->SetInteger(printing::kPreviewInitiatorHostId,
941 initiator->GetRenderProcessHost()->GetID());
942 settings->SetInteger(printing::kPreviewInitiatorRoutingId,
943 initiator->GetRoutingID());
946 ClearInitiatorDetails();
948 // The PDF being printed contains only the pages that the user selected,
949 // so ignore the page range and print all pages.
950 settings->Remove(printing::kSettingPageRange, NULL);
951 // Reset selection only flag for the same reason.
952 settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
954 // Set ID to know whether printing is for preview.
955 settings->SetInteger(printing::kPreviewUIID,
956 print_preview_ui->GetIDForPrintPreviewUI());
957 RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
958 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
959 *settings));
961 // For all other cases above, the preview dialog will stay open until the
962 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
963 // called. In the case below, since the preview dialog will be hidden and
964 // not closed, we need to make this call.
965 if (initiator) {
966 printing::PrintViewManager* print_view_manager =
967 printing::PrintViewManager::FromWebContents(initiator);
968 print_view_manager->PrintPreviewDone();
973 void PrintPreviewHandler::PrintToPdf() {
974 if (!print_to_pdf_path_.empty()) {
975 // User has already selected a path, no need to show the dialog again.
976 PostPrintToPdfTask();
977 } else if (!select_file_dialog_.get() ||
978 !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
979 preview_web_contents()->GetNativeView()))) {
980 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
981 web_ui()->GetController());
982 // Pre-populating select file dialog with print job title.
983 base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
985 #if defined(OS_WIN)
986 base::FilePath::StringType print_job_title(print_job_title_utf16);
987 #elif defined(OS_POSIX)
988 base::FilePath::StringType print_job_title =
989 base::UTF16ToUTF8(print_job_title_utf16);
990 #endif
992 base::i18n::ReplaceIllegalCharactersInPath(&print_job_title, '_');
993 base::FilePath default_filename(print_job_title);
994 default_filename =
995 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
997 SelectFile(default_filename);
1001 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
1002 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1003 web_ui()->GetController());
1004 print_preview_ui->OnHidePreviewDialog();
1007 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
1008 const base::ListValue* /*args*/) {
1009 WebContents* initiator = GetInitiator();
1010 if (initiator)
1011 ClearInitiatorDetails();
1012 chrome::ShowPrintErrorDialog();
1015 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
1016 std::string data_to_save;
1017 printing::StickySettings* sticky_settings = GetStickySettings();
1018 if (args->GetString(0, &data_to_save) && !data_to_save.empty())
1019 sticky_settings->StoreAppState(data_to_save);
1020 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1021 preview_web_contents()->GetBrowserContext())->GetPrefs());
1024 void PrintPreviewHandler::HandleGetPrinterCapabilities(
1025 const base::ListValue* args) {
1026 std::string printer_name;
1027 bool ret = args->GetString(0, &printer_name);
1028 if (!ret || printer_name.empty())
1029 return;
1031 GetPrinterCapabilitiesSuccessCallback success_cb =
1032 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
1033 weak_factory_.GetWeakPtr());
1034 GetPrinterCapabilitiesFailureCallback failure_cb =
1035 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
1036 weak_factory_.GetWeakPtr());
1037 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1038 base::Bind(&GetPrinterCapabilitiesOnFileThread,
1039 printer_name,
1040 g_browser_process->GetApplicationLocale(),
1041 success_cb, failure_cb));
1044 void PrintPreviewHandler::OnSigninComplete() {
1045 PrintPreviewUI* print_preview_ui =
1046 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1047 if (print_preview_ui)
1048 print_preview_ui->OnReloadPrintersList();
1051 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
1052 bool add_account = false;
1053 bool success = args->GetBoolean(0, &add_account);
1054 DCHECK(success);
1056 Profile* profile = Profile::FromBrowserContext(
1057 preview_web_contents()->GetBrowserContext());
1058 chrome::ScopedTabbedBrowserDisplayer displayer(
1059 profile, chrome::GetActiveDesktop());
1060 print_dialog_cloud::CreateCloudPrintSigninTab(
1061 displayer.browser(),
1062 add_account,
1063 base::Bind(&PrintPreviewHandler::OnSigninComplete,
1064 weak_factory_.GetWeakPtr()));
1067 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
1068 std::string type;
1069 if (!args->GetString(0, &type))
1070 return;
1071 if (!token_service_)
1072 token_service_.reset(new AccessTokenService(this));
1073 token_service_->RequestToken(type);
1076 void PrintPreviewHandler::HandleManageCloudPrint(
1077 const base::ListValue* args) {
1078 ++manage_cloud_printers_dialog_request_count_;
1079 GURL manage_url(cloud_devices::GetCloudPrintRelativeURL("manage.html"));
1080 std::string user;
1081 if (!args->GetString(0, &user))
1082 return;
1083 if (!user.empty())
1084 manage_url = net::AppendQueryParameter(manage_url, "user", user);
1085 preview_web_contents()->OpenURL(content::OpenURLParams(
1086 manage_url,
1087 content::Referrer(),
1088 NEW_FOREGROUND_TAB,
1089 ui::PAGE_TRANSITION_LINK,
1090 false));
1093 #if defined(ENABLE_BASIC_PRINTING)
1094 void PrintPreviewHandler::HandleShowSystemDialog(
1095 const base::ListValue* /*args*/) {
1096 ReportStats();
1097 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1099 WebContents* initiator = GetInitiator();
1100 if (!initiator)
1101 return;
1103 printing::PrintViewManager* print_view_manager =
1104 printing::PrintViewManager::FromWebContents(initiator);
1105 print_view_manager->set_observer(this);
1106 print_view_manager->PrintForSystemDialogNow();
1108 // Cancel the pending preview request if exists.
1109 PrintPreviewUI* print_preview_ui =
1110 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1111 print_preview_ui->OnCancelPendingPreviewRequest();
1113 #endif // ENABLE_BASIC_PRINTING
1115 void PrintPreviewHandler::HandleManagePrinters(
1116 const base::ListValue* /*args*/) {
1117 ++manage_printers_dialog_request_count_;
1118 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1121 void PrintPreviewHandler::HandleClosePreviewDialog(
1122 const base::ListValue* /*args*/) {
1123 ReportStats();
1124 ReportUserActionHistogram(CANCEL);
1126 // Record the number of times the user requests to regenerate preview data
1127 // before cancelling.
1128 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1129 regenerate_preview_request_count_);
1132 void PrintPreviewHandler::ReportStats() {
1133 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1134 manage_printers_dialog_request_count_);
1135 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1136 manage_cloud_printers_dialog_request_count_);
1139 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1140 base::DictionaryValue* settings) {
1142 // Getting the measurement system based on the locale.
1143 UErrorCode errorCode = U_ZERO_ERROR;
1144 const char* locale = g_browser_process->GetApplicationLocale().c_str();
1145 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1146 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1147 system = UMS_SI;
1149 // Getting the number formatting based on the locale and writing to
1150 // dictionary.
1151 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1152 settings->SetInteger(kMeasurementSystem, system);
1155 void PrintPreviewHandler::HandleGetInitialSettings(
1156 const base::ListValue* /*args*/) {
1157 // Send before SendInitialSettings to allow cloud printer auto select.
1158 SendCloudPrintEnabled();
1159 BrowserThread::PostTaskAndReplyWithResult(
1160 BrowserThread::FILE, FROM_HERE,
1161 base::Bind(&GetDefaultPrinterOnFileThread),
1162 base::Bind(&PrintPreviewHandler::SendInitialSettings,
1163 weak_factory_.GetWeakPtr()));
1166 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1167 std::string url;
1168 if (!args->GetString(0, &url))
1169 return;
1170 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1171 if (!browser)
1172 return;
1173 chrome::AddSelectedTabWithURL(browser,
1174 GURL(url),
1175 ui::PAGE_TRANSITION_LINK);
1178 void PrintPreviewHandler::SendInitialSettings(
1179 const std::string& default_printer) {
1180 PrintPreviewUI* print_preview_ui =
1181 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1183 base::DictionaryValue initial_settings;
1184 initial_settings.SetString(kInitiatorTitle,
1185 print_preview_ui->initiator_title());
1186 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1187 print_preview_ui->source_is_modifiable());
1188 initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1189 initial_settings.SetBoolean(kDocumentHasSelection,
1190 print_preview_ui->source_has_selection());
1191 initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1192 print_preview_ui->print_selection_only());
1193 printing::StickySettings* sticky_settings = GetStickySettings();
1194 sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1195 preview_web_contents()->GetBrowserContext())->GetPrefs());
1196 if (sticky_settings->printer_app_state()) {
1197 initial_settings.SetString(kAppState,
1198 *sticky_settings->printer_app_state());
1201 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1202 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1203 cmdline->HasSwitch(switches::kKioskModePrinting));
1204 initial_settings.SetBoolean(kAppKioskMode,
1205 chrome::IsRunningInForcedAppMode());
1206 #if defined(OS_WIN)
1207 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1208 // so will cause the browser to appear hung, so we don't show the link in
1209 // metro.
1210 bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1211 initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1212 #endif
1214 if (print_preview_ui->source_is_modifiable())
1215 GetNumberFormatAndMeasurementSystem(&initial_settings);
1216 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1219 void PrintPreviewHandler::ClosePreviewDialog() {
1220 PrintPreviewUI* print_preview_ui =
1221 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1222 print_preview_ui->OnClosePrintPreviewDialog();
1225 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1226 const std::string& access_token) {
1227 VLOG(1) << "Get getAccessToken finished";
1228 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1229 base::StringValue(type),
1230 base::StringValue(access_token));
1233 void PrintPreviewHandler::SendPrinterCapabilities(
1234 const base::DictionaryValue* settings_info) {
1235 VLOG(1) << "Get printer capabilities finished";
1236 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1237 *settings_info);
1240 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1241 const std::string& printer_name) {
1242 VLOG(1) << "Get printer capabilities failed";
1243 base::StringValue printer_name_value(printer_name);
1244 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1245 printer_name_value);
1248 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1249 if (!has_logged_printers_count_) {
1250 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1251 has_logged_printers_count_ = true;
1254 web_ui()->CallJavascriptFunction("setPrinters", *printers);
1257 void PrintPreviewHandler::SendCloudPrintEnabled() {
1258 Profile* profile = Profile::FromBrowserContext(
1259 preview_web_contents()->GetBrowserContext());
1260 PrefService* prefs = profile->GetPrefs();
1261 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1262 base::DictionaryValue settings;
1263 settings.SetString(kCloudPrintUrl,
1264 GURL(cloud_devices::GetCloudPrintURL()).spec());
1265 settings.SetBoolean(kAppKioskMode, chrome::IsRunningInForcedAppMode());
1266 web_ui()->CallJavascriptFunction("setUseCloudPrint", settings);
1270 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1271 // BASE64 encode the job data.
1272 std::string raw_data(reinterpret_cast<const char*>(data->front()),
1273 data->size());
1274 std::string base64_data;
1275 base::Base64Encode(raw_data, &base64_data);
1276 base::StringValue data_value(base64_data);
1278 web_ui()->CallJavascriptFunction("printToCloud", data_value);
1281 WebContents* PrintPreviewHandler::GetInitiator() const {
1282 printing::PrintPreviewDialogController* dialog_controller =
1283 printing::PrintPreviewDialogController::GetInstance();
1284 if (!dialog_controller)
1285 return NULL;
1286 return dialog_controller->GetInitiator(preview_web_contents());
1289 void PrintPreviewHandler::OnPrintDialogShown() {
1290 ClosePreviewDialog();
1293 void PrintPreviewHandler::MergeSessionCompleted(
1294 const std::string& account_id,
1295 const GoogleServiceAuthError& error) {
1296 OnSigninComplete();
1299 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
1300 ChromeSelectFilePolicy policy(GetInitiator());
1301 if (!policy.CanOpenSelectFileDialog()) {
1302 policy.SelectFileDenied();
1303 return ClosePreviewDialog();
1306 ui::SelectFileDialog::FileTypeInfo file_type_info;
1307 file_type_info.extensions.resize(1);
1308 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1310 // Initializing |save_path_| if it is not already initialized.
1311 printing::StickySettings* sticky_settings = GetStickySettings();
1312 if (!sticky_settings->save_path()) {
1313 // Allowing IO operation temporarily. It is ok to do so here because
1314 // the select file dialog performs IO anyway in order to display the
1315 // folders and also it is modal.
1316 base::ThreadRestrictions::ScopedAllowIO allow_io;
1317 base::FilePath file_path;
1318 PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1319 sticky_settings->StoreSavePath(file_path);
1320 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1321 preview_web_contents()->GetBrowserContext())->GetPrefs());
1324 select_file_dialog_ =
1325 ui::SelectFileDialog::Create(this, nullptr /*policy already checked*/);
1326 select_file_dialog_->SelectFile(
1327 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1328 base::string16(),
1329 sticky_settings->save_path()->Append(default_filename),
1330 &file_type_info,
1332 base::FilePath::StringType(),
1333 platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1334 NULL);
1337 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1338 WebContents* initiator = GetInitiator();
1339 if (!initiator)
1340 return;
1342 printing::PrintViewManager* print_view_manager =
1343 printing::PrintViewManager::FromWebContents(initiator);
1344 print_view_manager->set_observer(NULL);
1347 void PrintPreviewHandler::OnPrintPreviewFailed() {
1348 if (reported_failed_preview_)
1349 return;
1350 reported_failed_preview_ = true;
1351 ReportUserActionHistogram(PREVIEW_FAILED);
1354 #if defined(ENABLE_BASIC_PRINTING)
1355 void PrintPreviewHandler::ShowSystemDialog() {
1356 HandleShowSystemDialog(NULL);
1358 #endif // ENABLE_BASIC_PRINTING
1360 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1361 int index, void* params) {
1362 // Updating |save_path_| to the newly selected folder.
1363 printing::StickySettings* sticky_settings = GetStickySettings();
1364 sticky_settings->StoreSavePath(path.DirName());
1365 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1366 preview_web_contents()->GetBrowserContext())->GetPrefs());
1367 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1368 print_to_pdf_path_ = path;
1369 PostPrintToPdfTask();
1372 void PrintPreviewHandler::PostPrintToPdfTask() {
1373 scoped_refptr<base::RefCountedBytes> data;
1374 base::string16 title;
1375 if (!GetPreviewDataAndTitle(&data, &title)) {
1376 NOTREACHED() << "Preview data was checked before file dialog.";
1377 return;
1379 BrowserThread::PostTask(BrowserThread::FILE,
1380 FROM_HERE,
1381 base::Bind(&PrintToPdfCallback,
1382 data,
1383 print_to_pdf_path_,
1384 pdf_file_saved_closure_));
1385 print_to_pdf_path_ = base::FilePath();
1386 ClosePreviewDialog();
1389 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1390 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1391 web_ui()->GetController());
1392 print_preview_ui->OnFileSelectionCancelled();
1395 void PrintPreviewHandler::ClearInitiatorDetails() {
1396 WebContents* initiator = GetInitiator();
1397 if (!initiator)
1398 return;
1400 // We no longer require the initiator details. Remove those details associated
1401 // with the preview dialog to allow the initiator to create another preview
1402 // dialog.
1403 printing::PrintPreviewDialogController* dialog_controller =
1404 printing::PrintPreviewDialogController::GetInstance();
1405 if (dialog_controller)
1406 dialog_controller->EraseInitiatorInfo(preview_web_contents());
1409 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1410 scoped_refptr<base::RefCountedBytes>* data,
1411 base::string16* title) const {
1412 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1413 web_ui()->GetController());
1414 scoped_refptr<base::RefCountedBytes> tmp_data;
1415 print_preview_ui->GetPrintPreviewDataForIndex(
1416 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1418 if (!tmp_data.get()) {
1419 // Nothing to print, no preview available.
1420 return false;
1422 DCHECK(tmp_data->size() && tmp_data->front());
1424 *data = tmp_data;
1425 *title = print_preview_ui->initiator_title();
1426 return true;
1429 #if defined(ENABLE_SERVICE_DISCOVERY)
1431 void PrintPreviewHandler::StartPrivetLister(const scoped_refptr<
1432 local_discovery::ServiceDiscoverySharedClient>& client) {
1433 if (!PrivetPrintingEnabled())
1434 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1436 Profile* profile = Profile::FromWebUI(web_ui());
1437 DCHECK(!service_discovery_client_.get() ||
1438 service_discovery_client_.get() == client.get());
1439 service_discovery_client_ = client;
1440 printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
1441 service_discovery_client_.get(), profile->GetRequestContext(), this));
1442 printer_lister_->Start();
1445 void PrintPreviewHandler::LocalPrinterChanged(
1446 bool added,
1447 const std::string& name,
1448 bool has_local_printing,
1449 const local_discovery::DeviceDescription& description) {
1450 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1451 if (has_local_printing ||
1452 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) {
1453 base::DictionaryValue info;
1454 FillPrinterDescription(name, description, has_local_printing, &info);
1455 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1459 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1462 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1465 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1466 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1467 if (!PrivetUpdateClient(http_client.Pass()))
1468 return;
1470 privet_capabilities_operation_ =
1471 privet_http_client_->CreateCapabilitiesOperation(
1472 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1473 base::Unretained(this)));
1474 privet_capabilities_operation_->Start();
1477 bool PrintPreviewHandler::PrivetUpdateClient(
1478 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1479 if (!http_client) {
1480 SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1481 privet_http_resolution_.reset();
1482 return false;
1485 privet_local_print_operation_.reset();
1486 privet_capabilities_operation_.reset();
1487 privet_http_client_ =
1488 local_discovery::PrivetV1HTTPClient::CreateDefault(http_client.Pass());
1490 privet_http_resolution_.reset();
1492 return true;
1495 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1496 std::string print_ticket,
1497 std::string capabilities,
1498 gfx::Size page_size,
1499 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1500 if (!PrivetUpdateClient(http_client.Pass()))
1501 return;
1503 StartPrivetLocalPrint(print_ticket, capabilities, page_size);
1506 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string& print_ticket,
1507 const std::string& capabilities,
1508 const gfx::Size& page_size) {
1509 privet_local_print_operation_ =
1510 privet_http_client_->CreateLocalPrintOperation(this);
1512 privet_local_print_operation_->SetTicket(print_ticket);
1513 privet_local_print_operation_->SetCapabilities(capabilities);
1515 scoped_refptr<base::RefCountedBytes> data;
1516 base::string16 title;
1518 if (!GetPreviewDataAndTitle(&data, &title)) {
1519 base::FundamentalValue http_code_value(-1);
1520 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1521 return;
1524 privet_local_print_operation_->SetJobname(base::UTF16ToUTF8(title));
1525 privet_local_print_operation_->SetPageSize(page_size);
1526 privet_local_print_operation_->SetData(data.get());
1528 Profile* profile = Profile::FromWebUI(web_ui());
1529 SigninManagerBase* signin_manager =
1530 SigninManagerFactory::GetForProfileIfExists(profile);
1532 if (signin_manager) {
1533 privet_local_print_operation_->SetUsername(
1534 signin_manager->GetAuthenticatedUsername());
1537 privet_local_print_operation_->Start();
1541 void PrintPreviewHandler::OnPrivetCapabilities(
1542 const base::DictionaryValue* capabilities) {
1543 std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1545 if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError) ||
1546 !printer_lister_) {
1547 SendPrivetCapabilitiesError(name);
1548 return;
1551 base::DictionaryValue printer_info;
1552 const local_discovery::DeviceDescription* description =
1553 printer_lister_->GetDeviceDescription(name);
1555 if (!description) {
1556 SendPrivetCapabilitiesError(name);
1557 return;
1560 FillPrinterDescription(name, *description, true, &printer_info);
1562 web_ui()->CallJavascriptFunction(
1563 "onPrivetCapabilitiesSet",
1564 printer_info,
1565 *capabilities);
1567 privet_capabilities_operation_.reset();
1570 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1571 const std::string& device_name) {
1572 base::StringValue name_value(device_name);
1573 web_ui()->CallJavascriptFunction(
1574 "failedToGetPrivetPrinterCapabilities",
1575 name_value);
1578 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string& device_name,
1579 const std::string& ticket,
1580 const std::string& capabilities,
1581 const gfx::Size& page_size) {
1582 CreatePrivetHTTP(
1583 device_name,
1584 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1585 base::Unretained(this),
1586 ticket,
1587 capabilities,
1588 page_size));
1591 bool PrintPreviewHandler::CreatePrivetHTTP(
1592 const std::string& name,
1593 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1594 callback) {
1595 const local_discovery::DeviceDescription* device_description =
1596 printer_lister_ ? printer_lister_->GetDeviceDescription(name) : NULL;
1598 if (!device_description) {
1599 SendPrivetCapabilitiesError(name);
1600 return false;
1603 privet_http_factory_ =
1604 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1605 service_discovery_client_.get(),
1606 Profile::FromWebUI(web_ui())->GetRequestContext());
1607 privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
1608 name, device_description->address, callback);
1609 privet_http_resolution_->Start();
1611 return true;
1614 void PrintPreviewHandler::OnPrivetPrintingDone(
1615 const local_discovery::PrivetLocalPrintOperation* print_operation) {
1616 ClosePreviewDialog();
1619 void PrintPreviewHandler::OnPrivetPrintingError(
1620 const local_discovery::PrivetLocalPrintOperation* print_operation,
1621 int http_code) {
1622 base::FundamentalValue http_code_value(http_code);
1623 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1626 void PrintPreviewHandler::FillPrinterDescription(
1627 const std::string& name,
1628 const local_discovery::DeviceDescription& description,
1629 bool has_local_printing,
1630 base::DictionaryValue* printer_value) {
1631 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1633 printer_value->SetString("serviceName", name);
1634 printer_value->SetString("name", description.name);
1635 printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1636 printer_value->SetBoolean(
1637 "isUnregistered",
1638 description.id.empty() &&
1639 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos));
1640 printer_value->SetString("cloudID", description.id);
1643 #endif // defined(ENABLE_SERVICE_DISCOVERY)
1645 void PrintPreviewHandler::EnsureExtensionPrinterHandlerSet() {
1646 if (extension_printer_handler_.get())
1647 return;
1649 extension_printer_handler_ =
1650 PrinterHandler::CreateForExtensionPrinters(Profile::FromWebUI(web_ui()));
1653 void PrintPreviewHandler::OnGotPrintersForExtension(
1654 const base::ListValue& printers,
1655 bool done) {
1656 web_ui()->CallJavascriptFunction("onExtensionPrintersAdded", printers,
1657 base::FundamentalValue(done));
1660 void PrintPreviewHandler::OnGotExtensionPrinterCapabilities(
1661 const std::string& printer_id,
1662 const base::DictionaryValue& capabilities) {
1663 if (capabilities.empty()) {
1664 web_ui()->CallJavascriptFunction("failedToGetExtensionPrinterCapabilities",
1665 base::StringValue(printer_id));
1666 return;
1669 web_ui()->CallJavascriptFunction("onExtensionCapabilitiesSet",
1670 base::StringValue(printer_id), capabilities);
1673 void PrintPreviewHandler::OnExtensionPrintResult(bool success,
1674 const std::string& status) {
1675 if (success) {
1676 ClosePreviewDialog();
1677 return;
1680 // TODO(tbarzic): This function works for extension printers case too, but it
1681 // should be renamed to something more generic.
1682 web_ui()->CallJavascriptFunction("onPrivetPrintFailed",
1683 base::StringValue(status));
1686 void PrintPreviewHandler::RegisterForMergeSession() {
1687 DCHECK(!reconcilor_);
1688 Profile* profile = Profile::FromWebUI(web_ui());
1689 if (switches::IsEnableAccountConsistency() && !profile->IsOffTheRecord()) {
1690 reconcilor_ = AccountReconcilorFactory::GetForProfile(profile);
1691 if (reconcilor_)
1692 reconcilor_->AddMergeSessionObserver(this);
1696 void PrintPreviewHandler::UnregisterForMergeSession() {
1697 if (reconcilor_)
1698 reconcilor_->RemoveMergeSessionObserver(this);
1701 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1702 const base::Closure& closure) {
1703 pdf_file_saved_closure_ = closure;