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"
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/sticky_settings.h"
49 #include "chrome/common/chrome_paths.h"
50 #include "chrome/common/chrome_switches.h"
51 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
52 #include "chrome/common/cloud_print/cloud_print_constants.h"
53 #include "chrome/common/crash_keys.h"
54 #include "chrome/common/pref_names.h"
55 #include "chrome/common/print_messages.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/signin/core/browser/account_reconcilor.h"
60 #include "components/signin/core/browser/profile_oauth2_token_service.h"
61 #include "components/signin/core/browser/signin_manager.h"
62 #include "components/signin/core/common/profile_management_switches.h"
63 #include "content/public/browser/browser_context.h"
64 #include "content/public/browser/browser_thread.h"
65 #include "content/public/browser/navigation_controller.h"
66 #include "content/public/browser/navigation_entry.h"
67 #include "content/public/browser/render_process_host.h"
68 #include "content/public/browser/render_view_host.h"
69 #include "content/public/browser/web_contents.h"
70 #include "content/public/browser/web_ui.h"
71 #include "google_apis/gaia/oauth2_token_service.h"
72 #include "printing/backend/print_backend.h"
73 #include "printing/backend/print_backend_consts.h"
74 #include "printing/metafile.h"
75 #include "printing/pdf_metafile_skia.h"
76 #include "printing/pdf_render_settings.h"
77 #include "printing/print_settings.h"
78 #include "printing/printing_context.h"
79 #include "printing/units.h"
80 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
82 #if defined(OS_CHROMEOS)
83 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
84 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
87 #if defined(ENABLE_SERVICE_DISCOVERY)
88 #include "chrome/browser/local_discovery/privet_constants.h"
91 using content::BrowserThread;
92 using content::RenderViewHost;
93 using content::WebContents;
97 enum UserActionBuckets {
101 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
104 INITIATOR_CRASHED, // UNUSED
106 PRINT_WITH_CLOUD_PRINT,
108 USERACTION_BUCKET_BOUNDARY
111 enum PrintSettingsBuckets {
123 EXTERNAL_PDF_PREVIEW,
129 PRINT_SETTINGS_BUCKET_BOUNDARY
132 void ReportUserActionHistogram(enum UserActionBuckets event) {
133 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
134 USERACTION_BUCKET_BOUNDARY);
137 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
138 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
139 PRINT_SETTINGS_BUCKET_BOUNDARY);
142 // Name of a dictionary field holding cloud print related data;
143 const char kAppState[] = "appState";
144 // Name of a dictionary field holding the initiator title.
145 const char kInitiatorTitle[] = "initiatorTitle";
146 // Name of a dictionary field holding the measurement system according to the
148 const char kMeasurementSystem[] = "measurementSystem";
149 // Name of a dictionary field holding the number format according to the locale.
150 const char kNumberFormat[] = "numberFormat";
151 // Name of a dictionary field specifying whether to print automatically in
152 // kiosk mode. See http://crbug.com/31395.
153 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
154 // Dictionary field to indicate whether Chrome is running in forced app (app
155 // kiosk) mode. It's not the same as desktop Chrome kiosk (the one above).
156 const char kAppKioskMode[] = "appKioskMode";
157 // Dictionary field to store Cloud Print base URL.
158 const char kCloudPrintUrl[] = "cloudPrintUrl";
160 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
162 // Name of a dictionary field holding the state of selection for document.
163 const char kDocumentHasSelection[] = "documentHasSelection";
165 // Id of the predefined PDF printer.
166 const char kLocalPdfPrinterId[] = "Save as PDF";
168 // Additional printer capability setting keys.
169 const char kPrinterId[] = "printerId";
170 const char kPrinterCapabilities[] = "capabilities";
172 // Get the print job settings dictionary from |args|. The caller takes
173 // ownership of the returned DictionaryValue. Returns NULL on failure.
174 base::DictionaryValue* GetSettingsDictionary(const base::ListValue* args) {
175 std::string json_str;
176 if (!args->GetString(0, &json_str)) {
177 NOTREACHED() << "Could not read JSON argument";
180 if (json_str.empty()) {
181 NOTREACHED() << "Empty print job settings";
184 scoped_ptr<base::DictionaryValue> settings(
185 static_cast<base::DictionaryValue*>(
186 base::JSONReader::Read(json_str)));
187 if (!settings.get() || !settings->IsType(base::Value::TYPE_DICTIONARY)) {
188 NOTREACHED() << "Print job settings must be a dictionary.";
192 if (settings->empty()) {
193 NOTREACHED() << "Print job settings dictionary is empty";
197 return settings.release();
200 // Track the popularity of print settings and report the stats.
201 void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
202 ReportPrintSettingHistogram(TOTAL);
204 const base::ListValue* page_range_array = NULL;
205 if (settings.GetList(printing::kSettingPageRange, &page_range_array) &&
206 !page_range_array->empty()) {
207 ReportPrintSettingHistogram(PAGE_RANGE);
210 const base::DictionaryValue* media_size_value = NULL;
211 if (settings.GetDictionary(printing::kSettingMediaSize, &media_size_value) &&
212 !media_size_value->empty()) {
213 bool is_default = false;
214 if (media_size_value->GetBoolean(printing::kSettingMediaSizeIsDefault,
217 ReportPrintSettingHistogram(DEFAULT_MEDIA);
219 ReportPrintSettingHistogram(NON_DEFAULT_MEDIA);
223 bool landscape = false;
224 if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
225 ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
228 if (settings.GetInteger(printing::kSettingCopies, &copies) && copies > 1)
229 ReportPrintSettingHistogram(COPIES);
231 bool collate = false;
232 if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
233 ReportPrintSettingHistogram(COLLATE);
236 if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
237 ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
240 if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
241 ReportPrintSettingHistogram(
242 printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
245 int margins_type = 0;
246 if (settings.GetInteger(printing::kSettingMarginsType, &margins_type) &&
248 ReportPrintSettingHistogram(NON_DEFAULT_MARGINS);
251 bool headers = false;
252 if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
254 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
257 bool css_background = false;
258 if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
259 &css_background) && css_background) {
260 ReportPrintSettingHistogram(CSS_BACKGROUND);
263 bool selection_only = false;
264 if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
265 &selection_only) && selection_only) {
266 ReportPrintSettingHistogram(SELECTION_ONLY);
269 bool external_preview = false;
270 if (settings.GetBoolean(printing::kSettingOpenPDFInPreview,
271 &external_preview) && external_preview) {
272 ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW);
276 // Callback that stores a PDF file on disk.
277 void PrintToPdfCallback(const scoped_refptr<base::RefCountedBytes>& data,
278 const base::FilePath& path,
279 const base::Closure& pdf_file_saved_closure) {
280 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
281 printing::PdfMetafileSkia metafile;
282 metafile.InitFromData(static_cast<const void*>(data->front()), data->size());
283 base::File file(path,
284 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
285 metafile.SaveTo(&file);
286 if (!pdf_file_saved_closure.is_null())
287 pdf_file_saved_closure.Run();
290 std::string GetDefaultPrinterOnFileThread() {
291 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
293 scoped_refptr<printing::PrintBackend> print_backend(
294 printing::PrintBackend::CreateInstance(NULL));
296 std::string default_printer = print_backend->GetDefaultPrinterName();
297 VLOG(1) << "Default Printer: " << default_printer;
298 return default_printer;
301 class PrintingContextDelegate : public printing::PrintingContext::Delegate {
303 // PrintingContext::Delegate methods.
304 virtual gfx::NativeView GetParentView() OVERRIDE { return NULL; }
305 virtual std::string GetAppLocale() OVERRIDE {
306 return g_browser_process->GetApplicationLocale();
310 gfx::Size GetDefaultPdfMediaSizeMicrons() {
311 PrintingContextDelegate delegate;
312 scoped_ptr<printing::PrintingContext> printing_context(
313 printing::PrintingContext::Create(&delegate));
314 if (printing::PrintingContext::OK != printing_context->UsePdfSettings() ||
315 printing_context->settings().device_units_per_inch() <= 0) {
318 gfx::Size pdf_media_size = printing_context->GetPdfPaperSizeDeviceUnits();
319 float deviceMicronsPerDeviceUnit =
320 (printing::kHundrethsMMPerInch * 10.0f) /
321 printing_context->settings().device_units_per_inch();
322 return gfx::Size(pdf_media_size.width() * deviceMicronsPerDeviceUnit,
323 pdf_media_size.height() * deviceMicronsPerDeviceUnit);
326 typedef base::Callback<void(const base::DictionaryValue*)>
327 GetPdfCapabilitiesCallback;
329 scoped_ptr<base::DictionaryValue> GetPdfCapabilitiesOnFileThread(
330 const std::string& locale) {
331 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
333 cloud_devices::CloudDeviceDescription description;
334 using namespace cloud_devices::printer;
336 OrientationCapability orientation;
337 orientation.AddOption(cloud_devices::printer::PORTRAIT);
338 orientation.AddOption(cloud_devices::printer::LANDSCAPE);
339 orientation.AddDefaultOption(AUTO_ORIENTATION, true);
340 orientation.SaveTo(&description);
342 ColorCapability color;
344 Color standard_color(STANDARD_COLOR);
345 standard_color.vendor_id = base::IntToString(printing::COLOR);
346 color.AddDefaultOption(standard_color, true);
348 color.SaveTo(&description);
350 static const cloud_devices::printer::MediaType kPdfMedia[] = {
357 const gfx::Size default_media_size = GetDefaultPdfMediaSizeMicrons();
359 "", "", default_media_size.width(), default_media_size.height());
360 if (!default_media.MatchBySize() ||
362 kPdfMedia + arraysize(kPdfMedia),
363 default_media.type) == kPdfMedia + arraysize(kPdfMedia)) {
364 default_media = Media(locale == "en-US" ? NA_LETTER : ISO_A4);
366 MediaCapability media;
367 for (size_t i = 0; i < arraysize(kPdfMedia); ++i) {
368 Media media_option(kPdfMedia[i]);
369 media.AddDefaultOption(media_option,
370 default_media.type == media_option.type);
372 media.SaveTo(&description);
374 return scoped_ptr<base::DictionaryValue>(description.root().DeepCopy());
377 scoped_ptr<base::DictionaryValue> GetLocalPrinterCapabilitiesOnFileThread(
378 const std::string& printer_name) {
379 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
381 scoped_refptr<printing::PrintBackend> print_backend(
382 printing::PrintBackend::CreateInstance(NULL));
384 VLOG(1) << "Get printer capabilities start for " << printer_name;
385 crash_keys::ScopedPrinterInfo crash_key(
386 print_backend->GetPrinterDriverInfo(printer_name));
388 if (!print_backend->IsValidPrinter(printer_name)) {
389 LOG(WARNING) << "Invalid printer " << printer_name;
390 return scoped_ptr<base::DictionaryValue>();
393 printing::PrinterSemanticCapsAndDefaults info;
394 if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
395 LOG(WARNING) << "Failed to get capabilities for " << printer_name;
396 return scoped_ptr<base::DictionaryValue>();
399 scoped_ptr<base::DictionaryValue> description(
400 cloud_print::PrinterSemanticCapsAndDefaultsToCdd(info));
402 LOG(WARNING) << "Failed to convert capabilities for " << printer_name;
403 return scoped_ptr<base::DictionaryValue>();
406 return description.Pass();
409 void EnumeratePrintersOnFileThread(base::ListValue* printers) {
410 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
412 scoped_refptr<printing::PrintBackend> print_backend(
413 printing::PrintBackend::CreateInstance(NULL));
415 VLOG(1) << "Enumerate printers start";
416 printing::PrinterList printer_list;
417 print_backend->EnumeratePrinters(&printer_list);
419 for (printing::PrinterList::iterator it = printer_list.begin();
420 it != printer_list.end(); ++it) {
421 base::DictionaryValue* printer_info = new base::DictionaryValue;
422 printers->Append(printer_info);
423 std::string printer_name;
424 std::string printer_description;
425 #if defined(OS_MACOSX)
426 // On Mac, |it->printer_description| specifies the printer name and
427 // |it->printer_name| specifies the device name / printer queue name.
428 printer_name = it->printer_description;
429 if (!it->options[kDriverNameTagName].empty())
430 printer_description = it->options[kDriverNameTagName];
432 printer_name = it->printer_name;
433 printer_description = it->printer_description;
435 printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
436 printer_info->SetString(printing::kSettingPrinterDescription,
437 printer_description);
438 printer_info->SetString(printing::kSettingPrinterName, printer_name);
439 VLOG(1) << "Found printer " << printer_name
440 << " with device name " << it->printer_name;
442 base::DictionaryValue* options = new base::DictionaryValue;
443 printer_info->Set(printing::kSettingPrinterOptions, options);
444 for (std::map<std::string, std::string>::iterator opt = it->options.begin();
445 opt != it->options.end();
447 options->SetString(opt->first, opt->second);
450 VLOG(1) << "Found printer " << printer_name << " with device name "
453 VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
457 typedef base::Callback<void(const base::DictionaryValue*)>
458 GetPrinterCapabilitiesSuccessCallback;
459 typedef base::Callback<void(const std::string&)>
460 GetPrinterCapabilitiesFailureCallback;
462 void GetPrinterCapabilitiesOnFileThread(
463 const std::string& printer_name,
464 const std::string& locale,
465 const GetPrinterCapabilitiesSuccessCallback& success_cb,
466 const GetPrinterCapabilitiesFailureCallback& failure_cb) {
467 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
468 DCHECK(!printer_name.empty());
470 scoped_ptr<base::DictionaryValue> printer_capabilities(
471 printer_name == kLocalPdfPrinterId ?
472 GetPdfCapabilitiesOnFileThread(locale) :
473 GetLocalPrinterCapabilitiesOnFileThread(printer_name));
474 if (!printer_capabilities) {
475 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
476 base::Bind(failure_cb, printer_name));
480 scoped_ptr<base::DictionaryValue> printer_info(new base::DictionaryValue);
481 printer_info->SetString(kPrinterId, printer_name);
482 printer_info->Set(kPrinterCapabilities, printer_capabilities.release());
484 BrowserThread::PostTask(
485 BrowserThread::UI, FROM_HERE,
486 base::Bind(success_cb, base::Owned(printer_info.release())));
489 base::LazyInstance<printing::StickySettings> g_sticky_settings =
490 LAZY_INSTANCE_INITIALIZER;
492 printing::StickySettings* GetStickySettings() {
493 return g_sticky_settings.Pointer();
498 class PrintPreviewHandler::AccessTokenService
499 : public OAuth2TokenService::Consumer {
501 explicit AccessTokenService(PrintPreviewHandler* handler)
502 : OAuth2TokenService::Consumer("print_preview"),
506 void RequestToken(const std::string& type) {
507 if (requests_.find(type) != requests_.end())
508 return; // Already in progress.
510 OAuth2TokenService* service = NULL;
511 std::string account_id;
512 if (type == "profile") {
513 Profile* profile = Profile::FromWebUI(handler_->web_ui());
515 ProfileOAuth2TokenService* token_service =
516 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
517 SigninManagerBase* signin_manager =
518 SigninManagerFactory::GetInstance()->GetForProfile(profile);
519 account_id = signin_manager->GetAuthenticatedAccountId();
520 service = token_service;
522 } else if (type == "device") {
523 #if defined(OS_CHROMEOS)
524 chromeos::DeviceOAuth2TokenService* token_service =
525 chromeos::DeviceOAuth2TokenServiceFactory::Get();
526 account_id = token_service->GetRobotAccountId();
527 service = token_service;
532 OAuth2TokenService::ScopeSet oauth_scopes;
533 oauth_scopes.insert(cloud_devices::kCloudPrintAuthScope);
534 scoped_ptr<OAuth2TokenService::Request> request(
535 service->StartRequest(account_id, oauth_scopes, this));
536 requests_[type].reset(request.release());
538 handler_->SendAccessToken(type, std::string()); // Unknown type.
542 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
543 const std::string& access_token,
544 const base::Time& expiration_time) OVERRIDE {
545 OnServiceResponce(request, access_token);
548 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
549 const GoogleServiceAuthError& error) OVERRIDE {
550 OnServiceResponce(request, std::string());
554 void OnServiceResponce(const OAuth2TokenService::Request* request,
555 const std::string& access_token) {
556 for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
557 if (i->second == request) {
558 handler_->SendAccessToken(i->first, access_token);
566 typedef std::map<std::string,
567 linked_ptr<OAuth2TokenService::Request> > Requests;
569 PrintPreviewHandler* handler_;
571 DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
574 PrintPreviewHandler::PrintPreviewHandler()
575 : regenerate_preview_request_count_(0),
576 manage_printers_dialog_request_count_(0),
577 manage_cloud_printers_dialog_request_count_(0),
578 reported_failed_preview_(false),
579 has_logged_printers_count_(false),
581 weak_factory_(this) {
582 ReportUserActionHistogram(PREVIEW_STARTED);
585 PrintPreviewHandler::~PrintPreviewHandler() {
586 if (select_file_dialog_.get())
587 select_file_dialog_->ListenerDestroyed();
589 UnregisterForMergeSession();
592 void PrintPreviewHandler::RegisterMessages() {
593 web_ui()->RegisterMessageCallback("getPrinters",
594 base::Bind(&PrintPreviewHandler::HandleGetPrinters,
595 base::Unretained(this)));
596 web_ui()->RegisterMessageCallback("getPreview",
597 base::Bind(&PrintPreviewHandler::HandleGetPreview,
598 base::Unretained(this)));
599 web_ui()->RegisterMessageCallback("print",
600 base::Bind(&PrintPreviewHandler::HandlePrint,
601 base::Unretained(this)));
602 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
603 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
604 base::Unretained(this)));
605 #if !defined(DISABLE_BASIC_PRINTING)
606 web_ui()->RegisterMessageCallback("showSystemDialog",
607 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
608 base::Unretained(this)));
609 #endif // !DISABLE_BASIC_PRINTING
610 web_ui()->RegisterMessageCallback("signIn",
611 base::Bind(&PrintPreviewHandler::HandleSignin,
612 base::Unretained(this)));
613 web_ui()->RegisterMessageCallback("getAccessToken",
614 base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
615 base::Unretained(this)));
616 web_ui()->RegisterMessageCallback("manageCloudPrinters",
617 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
618 base::Unretained(this)));
619 web_ui()->RegisterMessageCallback("manageLocalPrinters",
620 base::Bind(&PrintPreviewHandler::HandleManagePrinters,
621 base::Unretained(this)));
622 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
623 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
624 base::Unretained(this)));
625 web_ui()->RegisterMessageCallback("hidePreview",
626 base::Bind(&PrintPreviewHandler::HandleHidePreview,
627 base::Unretained(this)));
628 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
629 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
630 base::Unretained(this)));
631 web_ui()->RegisterMessageCallback("saveAppState",
632 base::Bind(&PrintPreviewHandler::HandleSaveAppState,
633 base::Unretained(this)));
634 web_ui()->RegisterMessageCallback("getInitialSettings",
635 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
636 base::Unretained(this)));
637 web_ui()->RegisterMessageCallback("printWithCloudPrintDialog",
638 base::Bind(&PrintPreviewHandler::HandlePrintWithCloudPrintDialog,
639 base::Unretained(this)));
640 web_ui()->RegisterMessageCallback("forceOpenNewTab",
641 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
642 base::Unretained(this)));
643 web_ui()->RegisterMessageCallback("getPrivetPrinters",
644 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
645 base::Unretained(this)));
646 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
647 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
648 base::Unretained(this)));
649 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
650 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
651 base::Unretained(this)));
652 RegisterForMergeSession();
655 bool PrintPreviewHandler::PrivetPrintingEnabled() {
656 #if defined(ENABLE_SERVICE_DISCOVERY)
663 WebContents* PrintPreviewHandler::preview_web_contents() const {
664 return web_ui()->GetWebContents();
667 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
668 base::ListValue* results = new base::ListValue;
669 BrowserThread::PostTaskAndReply(
670 BrowserThread::FILE, FROM_HERE,
671 base::Bind(&EnumeratePrintersOnFileThread,
672 base::Unretained(results)),
673 base::Bind(&PrintPreviewHandler::SetupPrinterList,
674 weak_factory_.GetWeakPtr(),
675 base::Owned(results)));
678 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
679 if (!PrivetPrintingEnabled())
680 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
681 #if defined(ENABLE_SERVICE_DISCOVERY)
682 local_discovery::ServiceDiscoverySharedClient::GetInstanceWithoutAlert(
683 base::Bind(&PrintPreviewHandler::StartPrivetLister,
684 weak_factory_.GetWeakPtr()));
685 #endif // ENABLE_SERVICE_DISCOVERY
688 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
689 const base::ListValue* args) {
690 #if defined(ENABLE_SERVICE_DISCOVERY)
691 if (PrivetPrintingEnabled() && printer_lister_) {
692 printer_lister_->Stop();
697 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
698 const base::ListValue* args) {
699 #if defined(ENABLE_SERVICE_DISCOVERY)
701 bool success = args->GetString(0, &name);
706 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
707 base::Unretained(this)));
711 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
712 DCHECK_EQ(3U, args->GetSize());
713 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
717 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
720 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
721 web_ui()->GetController());
722 print_preview_ui->OnPrintPreviewRequest(request_id);
723 // Add an additional key in order to identify |print_preview_ui| later on
724 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
726 settings->SetInteger(printing::kPreviewUIID,
727 print_preview_ui->GetIDForPrintPreviewUI());
729 // Increment request count.
730 ++regenerate_preview_request_count_;
732 WebContents* initiator = GetInitiator();
734 ReportUserActionHistogram(INITIATOR_CLOSED);
735 print_preview_ui->OnClosePrintPreviewDialog();
739 // Retrieve the page title and url and send it to the renderer process if
740 // headers and footers are to be displayed.
741 bool display_header_footer = false;
742 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
743 &display_header_footer)) {
746 if (display_header_footer) {
747 settings->SetString(printing::kSettingHeaderFooterTitle,
748 initiator->GetTitle());
750 content::NavigationEntry* entry =
751 initiator->GetController().GetLastCommittedEntry();
753 url = entry->GetVirtualURL().spec();
754 settings->SetString(printing::kSettingHeaderFooterURL, url);
757 bool generate_draft_data = false;
758 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
759 &generate_draft_data);
762 if (!generate_draft_data) {
763 double draft_page_count_double = -1;
764 success = args->GetDouble(1, &draft_page_count_double);
766 int draft_page_count = static_cast<int>(draft_page_count_double);
768 bool preview_modifiable = false;
769 success = args->GetBoolean(2, &preview_modifiable);
772 if (draft_page_count != -1 && preview_modifiable &&
773 print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
774 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
778 VLOG(1) << "Print preview request start";
779 RenderViewHost* rvh = initiator->GetRenderViewHost();
780 rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
783 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
786 // Record the number of times the user requests to regenerate preview data
788 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
789 regenerate_preview_request_count_);
791 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
795 ReportPrintSettingsStats(*settings);
797 // Never try to add headers/footers here. It's already in the generated PDF.
798 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
800 bool print_to_pdf = false;
801 bool is_cloud_printer = false;
802 bool print_with_privet = false;
804 bool open_pdf_in_preview = false;
805 #if defined(OS_MACOSX)
806 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
809 if (!open_pdf_in_preview) {
810 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
811 settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
812 is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
816 settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
819 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
820 ReportUserActionHistogram(PRINT_TO_PDF);
825 #if defined(ENABLE_SERVICE_DISCOVERY)
826 if (print_with_privet && PrivetPrintingEnabled()) {
827 std::string printer_name;
828 std::string print_ticket;
829 std::string capabilities;
830 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
831 ReportUserActionHistogram(PRINT_WITH_PRIVET);
835 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
836 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
837 !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
838 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
839 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
840 width <= 0 || height <= 0) {
842 base::FundamentalValue http_code_value(-1);
843 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
847 PrintToPrivetPrinter(
848 printer_name, print_ticket, capabilities, gfx::Size(width, height));
853 scoped_refptr<base::RefCountedBytes> data;
854 base::string16 title;
855 if (!GetPreviewDataAndTitle(&data, &title)) {
856 // Nothing to print, no preview available.
860 if (is_cloud_printer) {
861 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
863 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
864 SendCloudPrintJob(data.get());
866 bool system_dialog = false;
867 settings->GetBoolean(printing::kSettingShowSystemDialog, &system_dialog);
869 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count);
870 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
872 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
873 ReportUserActionHistogram(PRINT_TO_PRINTER);
876 // This tries to activate the initiator as well, so do not clear the
877 // association with the initiator yet.
878 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
879 web_ui()->GetController());
880 print_preview_ui->OnHidePreviewDialog();
882 // Do this so the initiator can open a new print preview dialog, while the
883 // current print preview dialog is still handling its print job.
884 WebContents* initiator = GetInitiator();
886 // Save initiator IDs. |PrintingMessageFilter::OnUpdatePrintSettings|
887 // would be called when initiator info is cleared.
888 settings->SetInteger(printing::kPreviewInitiatorHostId,
889 initiator->GetRenderProcessHost()->GetID());
890 settings->SetInteger(printing::kPreviewInitiatorRoutingId,
891 initiator->GetRoutingID());
894 ClearInitiatorDetails();
896 // The PDF being printed contains only the pages that the user selected,
897 // so ignore the page range and print all pages.
898 settings->Remove(printing::kSettingPageRange, NULL);
899 // Reset selection only flag for the same reason.
900 settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
902 // Set ID to know whether printing is for preview.
903 settings->SetInteger(printing::kPreviewUIID,
904 print_preview_ui->GetIDForPrintPreviewUI());
905 RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
906 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
909 // For all other cases above, the preview dialog will stay open until the
910 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
911 // called. In the case below, since the preview dialog will be hidden and
912 // not closed, we need to make this call.
914 printing::PrintViewManager* print_view_manager =
915 printing::PrintViewManager::FromWebContents(initiator);
916 print_view_manager->PrintPreviewDone();
921 void PrintPreviewHandler::PrintToPdf() {
922 if (!print_to_pdf_path_.empty()) {
923 // User has already selected a path, no need to show the dialog again.
924 PostPrintToPdfTask();
925 } else if (!select_file_dialog_.get() ||
926 !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
927 preview_web_contents()->GetNativeView()))) {
928 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
929 web_ui()->GetController());
930 // Pre-populating select file dialog with print job title.
931 base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
934 base::FilePath::StringType print_job_title(print_job_title_utf16);
935 #elif defined(OS_POSIX)
936 base::FilePath::StringType print_job_title =
937 base::UTF16ToUTF8(print_job_title_utf16);
940 base::i18n::ReplaceIllegalCharactersInPath(&print_job_title, '_');
941 base::FilePath default_filename(print_job_title);
943 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
945 SelectFile(default_filename);
949 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
950 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
951 web_ui()->GetController());
952 print_preview_ui->OnHidePreviewDialog();
955 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
956 const base::ListValue* /*args*/) {
957 WebContents* initiator = GetInitiator();
959 ClearInitiatorDetails();
960 chrome::ShowPrintErrorDialog();
963 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
964 std::string data_to_save;
965 printing::StickySettings* sticky_settings = GetStickySettings();
966 if (args->GetString(0, &data_to_save) && !data_to_save.empty())
967 sticky_settings->StoreAppState(data_to_save);
968 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
969 preview_web_contents()->GetBrowserContext())->GetPrefs());
972 void PrintPreviewHandler::HandleGetPrinterCapabilities(
973 const base::ListValue* args) {
974 std::string printer_name;
975 bool ret = args->GetString(0, &printer_name);
976 if (!ret || printer_name.empty())
979 GetPrinterCapabilitiesSuccessCallback success_cb =
980 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
981 weak_factory_.GetWeakPtr());
982 GetPrinterCapabilitiesFailureCallback failure_cb =
983 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
984 weak_factory_.GetWeakPtr());
985 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
986 base::Bind(&GetPrinterCapabilitiesOnFileThread,
988 g_browser_process->GetApplicationLocale(),
989 success_cb, failure_cb));
992 void PrintPreviewHandler::OnSigninComplete() {
993 PrintPreviewUI* print_preview_ui =
994 static_cast<PrintPreviewUI*>(web_ui()->GetController());
995 if (print_preview_ui)
996 print_preview_ui->OnReloadPrintersList();
999 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
1000 bool add_account = false;
1001 bool success = args->GetBoolean(0, &add_account);
1004 Profile* profile = Profile::FromBrowserContext(
1005 preview_web_contents()->GetBrowserContext());
1006 chrome::ScopedTabbedBrowserDisplayer displayer(
1007 profile, chrome::GetActiveDesktop());
1008 print_dialog_cloud::CreateCloudPrintSigninTab(
1009 displayer.browser(),
1011 base::Bind(&PrintPreviewHandler::OnSigninComplete,
1012 weak_factory_.GetWeakPtr()));
1015 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
1017 if (!args->GetString(0, &type))
1019 if (!token_service_)
1020 token_service_.reset(new AccessTokenService(this));
1021 token_service_->RequestToken(type);
1024 void PrintPreviewHandler::PrintWithCloudPrintDialog() {
1025 // Record the number of times the user asks to print via cloud print
1026 // instead of the print preview dialog.
1029 scoped_refptr<base::RefCountedBytes> data;
1030 base::string16 title;
1031 if (!GetPreviewDataAndTitle(&data, &title)) {
1032 // Nothing to print, no preview available.
1036 gfx::NativeWindow modal_parent = platform_util::GetTopLevel(
1037 preview_web_contents()->GetNativeView());
1038 print_dialog_cloud::CreatePrintDialogForBytes(
1039 preview_web_contents()->GetBrowserContext(),
1044 std::string("application/pdf"));
1046 // Once the cloud print dialog comes up we're no longer in a background
1047 // printing situation. Close the print preview.
1048 // TODO(abodenha@chromium.org) The flow should be changed as described in
1049 // http://code.google.com/p/chromium/issues/detail?id=44093
1050 ClosePreviewDialog();
1053 void PrintPreviewHandler::HandleManageCloudPrint(
1054 const base::ListValue* /*args*/) {
1055 ++manage_cloud_printers_dialog_request_count_;
1056 preview_web_contents()->OpenURL(content::OpenURLParams(
1057 cloud_devices::GetCloudPrintRelativeURL("manage.html"),
1058 content::Referrer(),
1060 ui::PAGE_TRANSITION_LINK,
1064 #if !defined(DISABLE_BASIC_PRINTING)
1065 void PrintPreviewHandler::HandleShowSystemDialog(
1066 const base::ListValue* /*args*/) {
1068 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1070 WebContents* initiator = GetInitiator();
1074 printing::PrintViewManager* print_view_manager =
1075 printing::PrintViewManager::FromWebContents(initiator);
1076 print_view_manager->set_observer(this);
1077 print_view_manager->PrintForSystemDialogNow();
1079 // Cancel the pending preview request if exists.
1080 PrintPreviewUI* print_preview_ui =
1081 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1082 print_preview_ui->OnCancelPendingPreviewRequest();
1084 #endif // !DISABLE_BASIC_PRINTING
1086 void PrintPreviewHandler::HandleManagePrinters(
1087 const base::ListValue* /*args*/) {
1088 ++manage_printers_dialog_request_count_;
1089 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1092 void PrintPreviewHandler::HandlePrintWithCloudPrintDialog(
1093 const base::ListValue* args) {
1095 if (!args || !args->GetInteger(0, &page_count))
1097 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
1100 PrintWithCloudPrintDialog();
1103 void PrintPreviewHandler::HandleClosePreviewDialog(
1104 const base::ListValue* /*args*/) {
1106 ReportUserActionHistogram(CANCEL);
1108 // Record the number of times the user requests to regenerate preview data
1109 // before cancelling.
1110 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1111 regenerate_preview_request_count_);
1114 void PrintPreviewHandler::ReportStats() {
1115 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1116 manage_printers_dialog_request_count_);
1117 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1118 manage_cloud_printers_dialog_request_count_);
1121 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1122 base::DictionaryValue* settings) {
1124 // Getting the measurement system based on the locale.
1125 UErrorCode errorCode = U_ZERO_ERROR;
1126 const char* locale = g_browser_process->GetApplicationLocale().c_str();
1127 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1128 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1131 // Getting the number formatting based on the locale and writing to
1133 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1134 settings->SetInteger(kMeasurementSystem, system);
1137 void PrintPreviewHandler::HandleGetInitialSettings(
1138 const base::ListValue* /*args*/) {
1139 // Send before SendInitialSettings to allow cloud printer auto select.
1140 SendCloudPrintEnabled();
1141 BrowserThread::PostTaskAndReplyWithResult(
1142 BrowserThread::FILE, FROM_HERE,
1143 base::Bind(&GetDefaultPrinterOnFileThread),
1144 base::Bind(&PrintPreviewHandler::SendInitialSettings,
1145 weak_factory_.GetWeakPtr()));
1148 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1150 if (!args->GetString(0, &url))
1152 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1155 chrome::AddSelectedTabWithURL(browser,
1157 ui::PAGE_TRANSITION_LINK);
1160 void PrintPreviewHandler::SendInitialSettings(
1161 const std::string& default_printer) {
1162 PrintPreviewUI* print_preview_ui =
1163 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1165 base::DictionaryValue initial_settings;
1166 initial_settings.SetString(kInitiatorTitle,
1167 print_preview_ui->initiator_title());
1168 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1169 print_preview_ui->source_is_modifiable());
1170 initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1171 initial_settings.SetBoolean(kDocumentHasSelection,
1172 print_preview_ui->source_has_selection());
1173 initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1174 print_preview_ui->print_selection_only());
1175 printing::StickySettings* sticky_settings = GetStickySettings();
1176 sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1177 preview_web_contents()->GetBrowserContext())->GetPrefs());
1178 if (sticky_settings->printer_app_state()) {
1179 initial_settings.SetString(kAppState,
1180 *sticky_settings->printer_app_state());
1183 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1184 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1185 cmdline->HasSwitch(switches::kKioskModePrinting));
1186 initial_settings.SetBoolean(kAppKioskMode,
1187 chrome::IsRunningInForcedAppMode());
1189 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1190 // so will cause the browser to appear hung, so we don't show the link in
1192 bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1193 initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1196 if (print_preview_ui->source_is_modifiable())
1197 GetNumberFormatAndMeasurementSystem(&initial_settings);
1198 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1201 void PrintPreviewHandler::ClosePreviewDialog() {
1202 PrintPreviewUI* print_preview_ui =
1203 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1204 print_preview_ui->OnClosePrintPreviewDialog();
1207 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1208 const std::string& access_token) {
1209 VLOG(1) << "Get getAccessToken finished";
1210 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1211 base::StringValue(type),
1212 base::StringValue(access_token));
1215 void PrintPreviewHandler::SendPrinterCapabilities(
1216 const base::DictionaryValue* settings_info) {
1217 VLOG(1) << "Get printer capabilities finished";
1218 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1222 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1223 const std::string& printer_name) {
1224 VLOG(1) << "Get printer capabilities failed";
1225 base::StringValue printer_name_value(printer_name);
1226 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1227 printer_name_value);
1230 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1231 if (!has_logged_printers_count_) {
1232 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1233 has_logged_printers_count_ = true;
1236 web_ui()->CallJavascriptFunction("setPrinters", *printers);
1239 void PrintPreviewHandler::SendCloudPrintEnabled() {
1240 Profile* profile = Profile::FromBrowserContext(
1241 preview_web_contents()->GetBrowserContext());
1242 PrefService* prefs = profile->GetPrefs();
1243 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1244 base::DictionaryValue settings;
1245 settings.SetString(kCloudPrintUrl,
1246 GURL(cloud_devices::GetCloudPrintURL()).spec());
1247 settings.SetBoolean(kAppKioskMode, chrome::IsRunningInForcedAppMode());
1248 web_ui()->CallJavascriptFunction("setUseCloudPrint", settings);
1252 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1253 // BASE64 encode the job data.
1254 std::string raw_data(reinterpret_cast<const char*>(data->front()),
1256 std::string base64_data;
1257 base::Base64Encode(raw_data, &base64_data);
1258 base::StringValue data_value(base64_data);
1260 web_ui()->CallJavascriptFunction("printToCloud", data_value);
1263 WebContents* PrintPreviewHandler::GetInitiator() const {
1264 printing::PrintPreviewDialogController* dialog_controller =
1265 printing::PrintPreviewDialogController::GetInstance();
1266 if (!dialog_controller)
1268 return dialog_controller->GetInitiator(preview_web_contents());
1271 void PrintPreviewHandler::OnPrintDialogShown() {
1272 ClosePreviewDialog();
1275 void PrintPreviewHandler::MergeSessionCompleted(
1276 const std::string& account_id,
1277 const GoogleServiceAuthError& error) {
1281 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
1282 ui::SelectFileDialog::FileTypeInfo file_type_info;
1283 file_type_info.extensions.resize(1);
1284 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1286 // Initializing |save_path_| if it is not already initialized.
1287 printing::StickySettings* sticky_settings = GetStickySettings();
1288 if (!sticky_settings->save_path()) {
1289 // Allowing IO operation temporarily. It is ok to do so here because
1290 // the select file dialog performs IO anyway in order to display the
1291 // folders and also it is modal.
1292 base::ThreadRestrictions::ScopedAllowIO allow_io;
1293 base::FilePath file_path;
1294 PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1295 sticky_settings->StoreSavePath(file_path);
1296 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1297 preview_web_contents()->GetBrowserContext())->GetPrefs());
1300 select_file_dialog_ = ui::SelectFileDialog::Create(
1301 this, new ChromeSelectFilePolicy(preview_web_contents())),
1302 select_file_dialog_->SelectFile(
1303 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1305 sticky_settings->save_path()->Append(default_filename),
1308 base::FilePath::StringType(),
1309 platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1313 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1314 WebContents* initiator = GetInitiator();
1318 printing::PrintViewManager* print_view_manager =
1319 printing::PrintViewManager::FromWebContents(initiator);
1320 print_view_manager->set_observer(NULL);
1323 void PrintPreviewHandler::OnPrintPreviewFailed() {
1324 if (reported_failed_preview_)
1326 reported_failed_preview_ = true;
1327 ReportUserActionHistogram(PREVIEW_FAILED);
1330 #if !defined(DISABLE_BASIC_PRINTING)
1331 void PrintPreviewHandler::ShowSystemDialog() {
1332 HandleShowSystemDialog(NULL);
1334 #endif // !DISABLE_BASIC_PRINTING
1336 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1337 int index, void* params) {
1338 // Updating |save_path_| to the newly selected folder.
1339 printing::StickySettings* sticky_settings = GetStickySettings();
1340 sticky_settings->StoreSavePath(path.DirName());
1341 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1342 preview_web_contents()->GetBrowserContext())->GetPrefs());
1343 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1344 print_to_pdf_path_ = path;
1345 PostPrintToPdfTask();
1348 void PrintPreviewHandler::PostPrintToPdfTask() {
1349 scoped_refptr<base::RefCountedBytes> data;
1350 base::string16 title;
1351 if (!GetPreviewDataAndTitle(&data, &title)) {
1352 NOTREACHED() << "Preview data was checked before file dialog.";
1355 BrowserThread::PostTask(BrowserThread::FILE,
1357 base::Bind(&PrintToPdfCallback,
1360 pdf_file_saved_closure_));
1361 print_to_pdf_path_ = base::FilePath();
1362 ClosePreviewDialog();
1365 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1366 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1367 web_ui()->GetController());
1368 print_preview_ui->OnFileSelectionCancelled();
1371 void PrintPreviewHandler::ClearInitiatorDetails() {
1372 WebContents* initiator = GetInitiator();
1376 // We no longer require the initiator details. Remove those details associated
1377 // with the preview dialog to allow the initiator to create another preview
1379 printing::PrintPreviewDialogController* dialog_controller =
1380 printing::PrintPreviewDialogController::GetInstance();
1381 if (dialog_controller)
1382 dialog_controller->EraseInitiatorInfo(preview_web_contents());
1385 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1386 scoped_refptr<base::RefCountedBytes>* data,
1387 base::string16* title) const {
1388 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1389 web_ui()->GetController());
1390 scoped_refptr<base::RefCountedBytes> tmp_data;
1391 print_preview_ui->GetPrintPreviewDataForIndex(
1392 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1394 if (!tmp_data.get()) {
1395 // Nothing to print, no preview available.
1398 DCHECK(tmp_data->size() && tmp_data->front());
1401 *title = print_preview_ui->initiator_title();
1405 #if defined(ENABLE_SERVICE_DISCOVERY)
1407 void PrintPreviewHandler::StartPrivetLister(const scoped_refptr<
1408 local_discovery::ServiceDiscoverySharedClient>& client) {
1409 if (!PrivetPrintingEnabled())
1410 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1412 Profile* profile = Profile::FromWebUI(web_ui());
1413 DCHECK(!service_discovery_client_.get() ||
1414 service_discovery_client_.get() == client.get());
1415 service_discovery_client_ = client;
1416 printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
1417 service_discovery_client_.get(), profile->GetRequestContext(), this));
1418 printer_lister_->Start();
1421 void PrintPreviewHandler::LocalPrinterChanged(
1423 const std::string& name,
1424 bool has_local_printing,
1425 const local_discovery::DeviceDescription& description) {
1426 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1427 if (has_local_printing ||
1428 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) {
1429 base::DictionaryValue info;
1430 FillPrinterDescription(name, description, has_local_printing, &info);
1431 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1435 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1438 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1441 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1442 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1443 if (!PrivetUpdateClient(http_client.Pass()))
1446 privet_capabilities_operation_ =
1447 privet_http_client_->CreateCapabilitiesOperation(
1448 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1449 base::Unretained(this)));
1450 privet_capabilities_operation_->Start();
1453 bool PrintPreviewHandler::PrivetUpdateClient(
1454 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1456 SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1457 privet_http_resolution_.reset();
1461 privet_local_print_operation_.reset();
1462 privet_capabilities_operation_.reset();
1463 privet_http_client_ =
1464 local_discovery::PrivetV1HTTPClient::CreateDefault(http_client.Pass());
1466 privet_http_resolution_.reset();
1471 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1472 std::string print_ticket,
1473 std::string capabilities,
1474 gfx::Size page_size,
1475 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1476 if (!PrivetUpdateClient(http_client.Pass()))
1479 StartPrivetLocalPrint(print_ticket, capabilities, page_size);
1482 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string& print_ticket,
1483 const std::string& capabilities,
1484 const gfx::Size& page_size) {
1485 privet_local_print_operation_ =
1486 privet_http_client_->CreateLocalPrintOperation(this);
1488 privet_local_print_operation_->SetTicket(print_ticket);
1489 privet_local_print_operation_->SetCapabilities(capabilities);
1491 scoped_refptr<base::RefCountedBytes> data;
1492 base::string16 title;
1494 if (!GetPreviewDataAndTitle(&data, &title)) {
1495 base::FundamentalValue http_code_value(-1);
1496 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1500 privet_local_print_operation_->SetJobname(base::UTF16ToUTF8(title));
1501 privet_local_print_operation_->SetPageSize(page_size);
1502 privet_local_print_operation_->SetData(data.get());
1504 Profile* profile = Profile::FromWebUI(web_ui());
1505 SigninManagerBase* signin_manager =
1506 SigninManagerFactory::GetForProfileIfExists(profile);
1508 if (signin_manager) {
1509 privet_local_print_operation_->SetUsername(
1510 signin_manager->GetAuthenticatedUsername());
1513 privet_local_print_operation_->Start();
1517 void PrintPreviewHandler::OnPrivetCapabilities(
1518 const base::DictionaryValue* capabilities) {
1519 std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1521 if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError) ||
1523 SendPrivetCapabilitiesError(name);
1527 base::DictionaryValue printer_info;
1528 const local_discovery::DeviceDescription* description =
1529 printer_lister_->GetDeviceDescription(name);
1532 SendPrivetCapabilitiesError(name);
1536 FillPrinterDescription(name, *description, true, &printer_info);
1538 web_ui()->CallJavascriptFunction(
1539 "onPrivetCapabilitiesSet",
1543 privet_capabilities_operation_.reset();
1546 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1547 const std::string& device_name) {
1548 base::StringValue name_value(device_name);
1549 web_ui()->CallJavascriptFunction(
1550 "failedToGetPrivetPrinterCapabilities",
1554 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string& device_name,
1555 const std::string& ticket,
1556 const std::string& capabilities,
1557 const gfx::Size& page_size) {
1560 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1561 base::Unretained(this),
1567 bool PrintPreviewHandler::CreatePrivetHTTP(
1568 const std::string& name,
1569 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1571 const local_discovery::DeviceDescription* device_description =
1572 printer_lister_ ? printer_lister_->GetDeviceDescription(name) : NULL;
1574 if (!device_description) {
1575 SendPrivetCapabilitiesError(name);
1579 privet_http_factory_ =
1580 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1581 service_discovery_client_.get(),
1582 Profile::FromWebUI(web_ui())->GetRequestContext());
1583 privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
1584 name, device_description->address, callback);
1585 privet_http_resolution_->Start();
1590 void PrintPreviewHandler::OnPrivetPrintingDone(
1591 const local_discovery::PrivetLocalPrintOperation* print_operation) {
1592 ClosePreviewDialog();
1595 void PrintPreviewHandler::OnPrivetPrintingError(
1596 const local_discovery::PrivetLocalPrintOperation* print_operation,
1598 base::FundamentalValue http_code_value(http_code);
1599 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1602 void PrintPreviewHandler::FillPrinterDescription(
1603 const std::string& name,
1604 const local_discovery::DeviceDescription& description,
1605 bool has_local_printing,
1606 base::DictionaryValue* printer_value) {
1607 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1609 printer_value->SetString("serviceName", name);
1610 printer_value->SetString("name", description.name);
1611 printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1612 printer_value->SetBoolean(
1614 description.id.empty() &&
1615 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos));
1616 printer_value->SetString("cloudID", description.id);
1619 #endif // defined(ENABLE_SERVICE_DISCOVERY)
1621 void PrintPreviewHandler::RegisterForMergeSession() {
1622 DCHECK(!reconcilor_);
1623 Profile* profile = Profile::FromWebUI(web_ui());
1624 if (switches::IsEnableAccountConsistency() && !profile->IsOffTheRecord()) {
1625 reconcilor_ = AccountReconcilorFactory::GetForProfile(profile);
1627 reconcilor_->AddMergeSessionObserver(this);
1631 void PrintPreviewHandler::UnregisterForMergeSession() {
1633 reconcilor_->RemoveMergeSessionObserver(this);
1636 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1637 const base::Closure& closure) {
1638 pdf_file_saved_closure_ = closure;