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 gfx::NativeView GetParentView() override { return NULL; }
305 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 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 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(ENABLE_BASIC_PRINTING)
606 web_ui()->RegisterMessageCallback("showSystemDialog",
607 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
608 base::Unretained(this)));
609 #endif // ENABLE_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("forceOpenNewTab",
638 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
639 base::Unretained(this)));
640 web_ui()->RegisterMessageCallback("getPrivetPrinters",
641 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
642 base::Unretained(this)));
643 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
644 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
645 base::Unretained(this)));
646 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
647 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
648 base::Unretained(this)));
649 RegisterForMergeSession();
652 bool PrintPreviewHandler::PrivetPrintingEnabled() {
653 #if defined(ENABLE_SERVICE_DISCOVERY)
660 WebContents* PrintPreviewHandler::preview_web_contents() const {
661 return web_ui()->GetWebContents();
664 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
665 base::ListValue* results = new base::ListValue;
666 BrowserThread::PostTaskAndReply(
667 BrowserThread::FILE, FROM_HERE,
668 base::Bind(&EnumeratePrintersOnFileThread,
669 base::Unretained(results)),
670 base::Bind(&PrintPreviewHandler::SetupPrinterList,
671 weak_factory_.GetWeakPtr(),
672 base::Owned(results)));
675 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
676 if (!PrivetPrintingEnabled())
677 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
678 #if defined(ENABLE_SERVICE_DISCOVERY)
679 local_discovery::ServiceDiscoverySharedClient::GetInstanceWithoutAlert(
680 base::Bind(&PrintPreviewHandler::StartPrivetLister,
681 weak_factory_.GetWeakPtr()));
682 #endif // ENABLE_SERVICE_DISCOVERY
685 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
686 const base::ListValue* args) {
687 #if defined(ENABLE_SERVICE_DISCOVERY)
688 if (PrivetPrintingEnabled() && printer_lister_) {
689 printer_lister_->Stop();
694 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
695 const base::ListValue* args) {
696 #if defined(ENABLE_SERVICE_DISCOVERY)
698 bool success = args->GetString(0, &name);
703 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
704 base::Unretained(this)));
708 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
709 DCHECK_EQ(3U, args->GetSize());
710 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
714 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
717 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
718 web_ui()->GetController());
719 print_preview_ui->OnPrintPreviewRequest(request_id);
720 // Add an additional key in order to identify |print_preview_ui| later on
721 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
723 settings->SetInteger(printing::kPreviewUIID,
724 print_preview_ui->GetIDForPrintPreviewUI());
726 // Increment request count.
727 ++regenerate_preview_request_count_;
729 WebContents* initiator = GetInitiator();
731 ReportUserActionHistogram(INITIATOR_CLOSED);
732 print_preview_ui->OnClosePrintPreviewDialog();
736 // Retrieve the page title and url and send it to the renderer process if
737 // headers and footers are to be displayed.
738 bool display_header_footer = false;
739 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
740 &display_header_footer)) {
743 if (display_header_footer) {
744 settings->SetString(printing::kSettingHeaderFooterTitle,
745 initiator->GetTitle());
747 content::NavigationEntry* entry =
748 initiator->GetController().GetLastCommittedEntry();
750 url = entry->GetVirtualURL().spec();
751 settings->SetString(printing::kSettingHeaderFooterURL, url);
754 bool generate_draft_data = false;
755 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
756 &generate_draft_data);
759 if (!generate_draft_data) {
760 double draft_page_count_double = -1;
761 success = args->GetDouble(1, &draft_page_count_double);
763 int draft_page_count = static_cast<int>(draft_page_count_double);
765 bool preview_modifiable = false;
766 success = args->GetBoolean(2, &preview_modifiable);
769 if (draft_page_count != -1 && preview_modifiable &&
770 print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
771 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
775 VLOG(1) << "Print preview request start";
776 RenderViewHost* rvh = initiator->GetRenderViewHost();
777 rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
780 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
783 // Record the number of times the user requests to regenerate preview data
785 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
786 regenerate_preview_request_count_);
788 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
792 ReportPrintSettingsStats(*settings);
794 // Never try to add headers/footers here. It's already in the generated PDF.
795 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
797 bool print_to_pdf = false;
798 bool is_cloud_printer = false;
799 bool print_with_privet = false;
801 bool open_pdf_in_preview = false;
802 #if defined(OS_MACOSX)
803 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
806 if (!open_pdf_in_preview) {
807 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
808 settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
809 is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
813 settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
816 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
817 ReportUserActionHistogram(PRINT_TO_PDF);
822 #if defined(ENABLE_SERVICE_DISCOVERY)
823 if (print_with_privet && PrivetPrintingEnabled()) {
824 std::string printer_name;
825 std::string print_ticket;
826 std::string capabilities;
827 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
828 ReportUserActionHistogram(PRINT_WITH_PRIVET);
832 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
833 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
834 !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
835 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
836 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
837 width <= 0 || height <= 0) {
839 base::FundamentalValue http_code_value(-1);
840 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
844 PrintToPrivetPrinter(
845 printer_name, print_ticket, capabilities, gfx::Size(width, height));
850 scoped_refptr<base::RefCountedBytes> data;
851 base::string16 title;
852 if (!GetPreviewDataAndTitle(&data, &title)) {
853 // Nothing to print, no preview available.
857 if (is_cloud_printer) {
858 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
860 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
861 SendCloudPrintJob(data.get());
863 bool system_dialog = false;
864 settings->GetBoolean(printing::kSettingShowSystemDialog, &system_dialog);
866 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count);
867 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
869 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
870 ReportUserActionHistogram(PRINT_TO_PRINTER);
873 // This tries to activate the initiator as well, so do not clear the
874 // association with the initiator yet.
875 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
876 web_ui()->GetController());
877 print_preview_ui->OnHidePreviewDialog();
879 // Do this so the initiator can open a new print preview dialog, while the
880 // current print preview dialog is still handling its print job.
881 WebContents* initiator = GetInitiator();
883 // Save initiator IDs. |PrintingMessageFilter::OnUpdatePrintSettings|
884 // would be called when initiator info is cleared.
885 settings->SetInteger(printing::kPreviewInitiatorHostId,
886 initiator->GetRenderProcessHost()->GetID());
887 settings->SetInteger(printing::kPreviewInitiatorRoutingId,
888 initiator->GetRoutingID());
891 ClearInitiatorDetails();
893 // The PDF being printed contains only the pages that the user selected,
894 // so ignore the page range and print all pages.
895 settings->Remove(printing::kSettingPageRange, NULL);
896 // Reset selection only flag for the same reason.
897 settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
899 // Set ID to know whether printing is for preview.
900 settings->SetInteger(printing::kPreviewUIID,
901 print_preview_ui->GetIDForPrintPreviewUI());
902 RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
903 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
906 // For all other cases above, the preview dialog will stay open until the
907 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
908 // called. In the case below, since the preview dialog will be hidden and
909 // not closed, we need to make this call.
911 printing::PrintViewManager* print_view_manager =
912 printing::PrintViewManager::FromWebContents(initiator);
913 print_view_manager->PrintPreviewDone();
918 void PrintPreviewHandler::PrintToPdf() {
919 if (!print_to_pdf_path_.empty()) {
920 // User has already selected a path, no need to show the dialog again.
921 PostPrintToPdfTask();
922 } else if (!select_file_dialog_.get() ||
923 !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
924 preview_web_contents()->GetNativeView()))) {
925 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
926 web_ui()->GetController());
927 // Pre-populating select file dialog with print job title.
928 base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
931 base::FilePath::StringType print_job_title(print_job_title_utf16);
932 #elif defined(OS_POSIX)
933 base::FilePath::StringType print_job_title =
934 base::UTF16ToUTF8(print_job_title_utf16);
937 base::i18n::ReplaceIllegalCharactersInPath(&print_job_title, '_');
938 base::FilePath default_filename(print_job_title);
940 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
942 SelectFile(default_filename);
946 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
947 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
948 web_ui()->GetController());
949 print_preview_ui->OnHidePreviewDialog();
952 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
953 const base::ListValue* /*args*/) {
954 WebContents* initiator = GetInitiator();
956 ClearInitiatorDetails();
957 chrome::ShowPrintErrorDialog();
960 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
961 std::string data_to_save;
962 printing::StickySettings* sticky_settings = GetStickySettings();
963 if (args->GetString(0, &data_to_save) && !data_to_save.empty())
964 sticky_settings->StoreAppState(data_to_save);
965 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
966 preview_web_contents()->GetBrowserContext())->GetPrefs());
969 void PrintPreviewHandler::HandleGetPrinterCapabilities(
970 const base::ListValue* args) {
971 std::string printer_name;
972 bool ret = args->GetString(0, &printer_name);
973 if (!ret || printer_name.empty())
976 GetPrinterCapabilitiesSuccessCallback success_cb =
977 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
978 weak_factory_.GetWeakPtr());
979 GetPrinterCapabilitiesFailureCallback failure_cb =
980 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
981 weak_factory_.GetWeakPtr());
982 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
983 base::Bind(&GetPrinterCapabilitiesOnFileThread,
985 g_browser_process->GetApplicationLocale(),
986 success_cb, failure_cb));
989 void PrintPreviewHandler::OnSigninComplete() {
990 PrintPreviewUI* print_preview_ui =
991 static_cast<PrintPreviewUI*>(web_ui()->GetController());
992 if (print_preview_ui)
993 print_preview_ui->OnReloadPrintersList();
996 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
997 bool add_account = false;
998 bool success = args->GetBoolean(0, &add_account);
1001 Profile* profile = Profile::FromBrowserContext(
1002 preview_web_contents()->GetBrowserContext());
1003 chrome::ScopedTabbedBrowserDisplayer displayer(
1004 profile, chrome::GetActiveDesktop());
1005 print_dialog_cloud::CreateCloudPrintSigninTab(
1006 displayer.browser(),
1008 base::Bind(&PrintPreviewHandler::OnSigninComplete,
1009 weak_factory_.GetWeakPtr()));
1012 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
1014 if (!args->GetString(0, &type))
1016 if (!token_service_)
1017 token_service_.reset(new AccessTokenService(this));
1018 token_service_->RequestToken(type);
1021 void PrintPreviewHandler::HandleManageCloudPrint(
1022 const base::ListValue* /*args*/) {
1023 ++manage_cloud_printers_dialog_request_count_;
1024 preview_web_contents()->OpenURL(content::OpenURLParams(
1025 cloud_devices::GetCloudPrintRelativeURL("manage.html"),
1026 content::Referrer(),
1028 ui::PAGE_TRANSITION_LINK,
1032 #if defined(ENABLE_BASIC_PRINTING)
1033 void PrintPreviewHandler::HandleShowSystemDialog(
1034 const base::ListValue* /*args*/) {
1036 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1038 WebContents* initiator = GetInitiator();
1042 printing::PrintViewManager* print_view_manager =
1043 printing::PrintViewManager::FromWebContents(initiator);
1044 print_view_manager->set_observer(this);
1045 print_view_manager->PrintForSystemDialogNow();
1047 // Cancel the pending preview request if exists.
1048 PrintPreviewUI* print_preview_ui =
1049 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1050 print_preview_ui->OnCancelPendingPreviewRequest();
1052 #endif // ENABLE_BASIC_PRINTING
1054 void PrintPreviewHandler::HandleManagePrinters(
1055 const base::ListValue* /*args*/) {
1056 ++manage_printers_dialog_request_count_;
1057 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1060 void PrintPreviewHandler::HandleClosePreviewDialog(
1061 const base::ListValue* /*args*/) {
1063 ReportUserActionHistogram(CANCEL);
1065 // Record the number of times the user requests to regenerate preview data
1066 // before cancelling.
1067 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1068 regenerate_preview_request_count_);
1071 void PrintPreviewHandler::ReportStats() {
1072 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1073 manage_printers_dialog_request_count_);
1074 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1075 manage_cloud_printers_dialog_request_count_);
1078 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1079 base::DictionaryValue* settings) {
1081 // Getting the measurement system based on the locale.
1082 UErrorCode errorCode = U_ZERO_ERROR;
1083 const char* locale = g_browser_process->GetApplicationLocale().c_str();
1084 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1085 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1088 // Getting the number formatting based on the locale and writing to
1090 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1091 settings->SetInteger(kMeasurementSystem, system);
1094 void PrintPreviewHandler::HandleGetInitialSettings(
1095 const base::ListValue* /*args*/) {
1096 // Send before SendInitialSettings to allow cloud printer auto select.
1097 SendCloudPrintEnabled();
1098 BrowserThread::PostTaskAndReplyWithResult(
1099 BrowserThread::FILE, FROM_HERE,
1100 base::Bind(&GetDefaultPrinterOnFileThread),
1101 base::Bind(&PrintPreviewHandler::SendInitialSettings,
1102 weak_factory_.GetWeakPtr()));
1105 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1107 if (!args->GetString(0, &url))
1109 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1112 chrome::AddSelectedTabWithURL(browser,
1114 ui::PAGE_TRANSITION_LINK);
1117 void PrintPreviewHandler::SendInitialSettings(
1118 const std::string& default_printer) {
1119 PrintPreviewUI* print_preview_ui =
1120 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1122 base::DictionaryValue initial_settings;
1123 initial_settings.SetString(kInitiatorTitle,
1124 print_preview_ui->initiator_title());
1125 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1126 print_preview_ui->source_is_modifiable());
1127 initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1128 initial_settings.SetBoolean(kDocumentHasSelection,
1129 print_preview_ui->source_has_selection());
1130 initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1131 print_preview_ui->print_selection_only());
1132 printing::StickySettings* sticky_settings = GetStickySettings();
1133 sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1134 preview_web_contents()->GetBrowserContext())->GetPrefs());
1135 if (sticky_settings->printer_app_state()) {
1136 initial_settings.SetString(kAppState,
1137 *sticky_settings->printer_app_state());
1140 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1141 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1142 cmdline->HasSwitch(switches::kKioskModePrinting));
1143 initial_settings.SetBoolean(kAppKioskMode,
1144 chrome::IsRunningInForcedAppMode());
1146 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1147 // so will cause the browser to appear hung, so we don't show the link in
1149 bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1150 initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1153 if (print_preview_ui->source_is_modifiable())
1154 GetNumberFormatAndMeasurementSystem(&initial_settings);
1155 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1158 void PrintPreviewHandler::ClosePreviewDialog() {
1159 PrintPreviewUI* print_preview_ui =
1160 static_cast<PrintPreviewUI*>(web_ui()->GetController());
1161 print_preview_ui->OnClosePrintPreviewDialog();
1164 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1165 const std::string& access_token) {
1166 VLOG(1) << "Get getAccessToken finished";
1167 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1168 base::StringValue(type),
1169 base::StringValue(access_token));
1172 void PrintPreviewHandler::SendPrinterCapabilities(
1173 const base::DictionaryValue* settings_info) {
1174 VLOG(1) << "Get printer capabilities finished";
1175 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1179 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1180 const std::string& printer_name) {
1181 VLOG(1) << "Get printer capabilities failed";
1182 base::StringValue printer_name_value(printer_name);
1183 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1184 printer_name_value);
1187 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1188 if (!has_logged_printers_count_) {
1189 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1190 has_logged_printers_count_ = true;
1193 web_ui()->CallJavascriptFunction("setPrinters", *printers);
1196 void PrintPreviewHandler::SendCloudPrintEnabled() {
1197 Profile* profile = Profile::FromBrowserContext(
1198 preview_web_contents()->GetBrowserContext());
1199 PrefService* prefs = profile->GetPrefs();
1200 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1201 base::DictionaryValue settings;
1202 settings.SetString(kCloudPrintUrl,
1203 GURL(cloud_devices::GetCloudPrintURL()).spec());
1204 settings.SetBoolean(kAppKioskMode, chrome::IsRunningInForcedAppMode());
1205 web_ui()->CallJavascriptFunction("setUseCloudPrint", settings);
1209 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1210 // BASE64 encode the job data.
1211 std::string raw_data(reinterpret_cast<const char*>(data->front()),
1213 std::string base64_data;
1214 base::Base64Encode(raw_data, &base64_data);
1215 base::StringValue data_value(base64_data);
1217 web_ui()->CallJavascriptFunction("printToCloud", data_value);
1220 WebContents* PrintPreviewHandler::GetInitiator() const {
1221 printing::PrintPreviewDialogController* dialog_controller =
1222 printing::PrintPreviewDialogController::GetInstance();
1223 if (!dialog_controller)
1225 return dialog_controller->GetInitiator(preview_web_contents());
1228 void PrintPreviewHandler::OnPrintDialogShown() {
1229 ClosePreviewDialog();
1232 void PrintPreviewHandler::MergeSessionCompleted(
1233 const std::string& account_id,
1234 const GoogleServiceAuthError& error) {
1238 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
1239 ui::SelectFileDialog::FileTypeInfo file_type_info;
1240 file_type_info.extensions.resize(1);
1241 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1243 // Initializing |save_path_| if it is not already initialized.
1244 printing::StickySettings* sticky_settings = GetStickySettings();
1245 if (!sticky_settings->save_path()) {
1246 // Allowing IO operation temporarily. It is ok to do so here because
1247 // the select file dialog performs IO anyway in order to display the
1248 // folders and also it is modal.
1249 base::ThreadRestrictions::ScopedAllowIO allow_io;
1250 base::FilePath file_path;
1251 PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1252 sticky_settings->StoreSavePath(file_path);
1253 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1254 preview_web_contents()->GetBrowserContext())->GetPrefs());
1257 select_file_dialog_ = ui::SelectFileDialog::Create(
1258 this, new ChromeSelectFilePolicy(preview_web_contents())),
1259 select_file_dialog_->SelectFile(
1260 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1262 sticky_settings->save_path()->Append(default_filename),
1265 base::FilePath::StringType(),
1266 platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1270 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1271 WebContents* initiator = GetInitiator();
1275 printing::PrintViewManager* print_view_manager =
1276 printing::PrintViewManager::FromWebContents(initiator);
1277 print_view_manager->set_observer(NULL);
1280 void PrintPreviewHandler::OnPrintPreviewFailed() {
1281 if (reported_failed_preview_)
1283 reported_failed_preview_ = true;
1284 ReportUserActionHistogram(PREVIEW_FAILED);
1287 #if defined(ENABLE_BASIC_PRINTING)
1288 void PrintPreviewHandler::ShowSystemDialog() {
1289 HandleShowSystemDialog(NULL);
1291 #endif // ENABLE_BASIC_PRINTING
1293 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1294 int index, void* params) {
1295 // Updating |save_path_| to the newly selected folder.
1296 printing::StickySettings* sticky_settings = GetStickySettings();
1297 sticky_settings->StoreSavePath(path.DirName());
1298 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1299 preview_web_contents()->GetBrowserContext())->GetPrefs());
1300 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1301 print_to_pdf_path_ = path;
1302 PostPrintToPdfTask();
1305 void PrintPreviewHandler::PostPrintToPdfTask() {
1306 scoped_refptr<base::RefCountedBytes> data;
1307 base::string16 title;
1308 if (!GetPreviewDataAndTitle(&data, &title)) {
1309 NOTREACHED() << "Preview data was checked before file dialog.";
1312 BrowserThread::PostTask(BrowserThread::FILE,
1314 base::Bind(&PrintToPdfCallback,
1317 pdf_file_saved_closure_));
1318 print_to_pdf_path_ = base::FilePath();
1319 ClosePreviewDialog();
1322 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1323 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1324 web_ui()->GetController());
1325 print_preview_ui->OnFileSelectionCancelled();
1328 void PrintPreviewHandler::ClearInitiatorDetails() {
1329 WebContents* initiator = GetInitiator();
1333 // We no longer require the initiator details. Remove those details associated
1334 // with the preview dialog to allow the initiator to create another preview
1336 printing::PrintPreviewDialogController* dialog_controller =
1337 printing::PrintPreviewDialogController::GetInstance();
1338 if (dialog_controller)
1339 dialog_controller->EraseInitiatorInfo(preview_web_contents());
1342 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1343 scoped_refptr<base::RefCountedBytes>* data,
1344 base::string16* title) const {
1345 PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1346 web_ui()->GetController());
1347 scoped_refptr<base::RefCountedBytes> tmp_data;
1348 print_preview_ui->GetPrintPreviewDataForIndex(
1349 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1351 if (!tmp_data.get()) {
1352 // Nothing to print, no preview available.
1355 DCHECK(tmp_data->size() && tmp_data->front());
1358 *title = print_preview_ui->initiator_title();
1362 #if defined(ENABLE_SERVICE_DISCOVERY)
1364 void PrintPreviewHandler::StartPrivetLister(const scoped_refptr<
1365 local_discovery::ServiceDiscoverySharedClient>& client) {
1366 if (!PrivetPrintingEnabled())
1367 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1369 Profile* profile = Profile::FromWebUI(web_ui());
1370 DCHECK(!service_discovery_client_.get() ||
1371 service_discovery_client_.get() == client.get());
1372 service_discovery_client_ = client;
1373 printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
1374 service_discovery_client_.get(), profile->GetRequestContext(), this));
1375 printer_lister_->Start();
1378 void PrintPreviewHandler::LocalPrinterChanged(
1380 const std::string& name,
1381 bool has_local_printing,
1382 const local_discovery::DeviceDescription& description) {
1383 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1384 if (has_local_printing ||
1385 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) {
1386 base::DictionaryValue info;
1387 FillPrinterDescription(name, description, has_local_printing, &info);
1388 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1392 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1395 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1398 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1399 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1400 if (!PrivetUpdateClient(http_client.Pass()))
1403 privet_capabilities_operation_ =
1404 privet_http_client_->CreateCapabilitiesOperation(
1405 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1406 base::Unretained(this)));
1407 privet_capabilities_operation_->Start();
1410 bool PrintPreviewHandler::PrivetUpdateClient(
1411 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1413 SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1414 privet_http_resolution_.reset();
1418 privet_local_print_operation_.reset();
1419 privet_capabilities_operation_.reset();
1420 privet_http_client_ =
1421 local_discovery::PrivetV1HTTPClient::CreateDefault(http_client.Pass());
1423 privet_http_resolution_.reset();
1428 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1429 std::string print_ticket,
1430 std::string capabilities,
1431 gfx::Size page_size,
1432 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1433 if (!PrivetUpdateClient(http_client.Pass()))
1436 StartPrivetLocalPrint(print_ticket, capabilities, page_size);
1439 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string& print_ticket,
1440 const std::string& capabilities,
1441 const gfx::Size& page_size) {
1442 privet_local_print_operation_ =
1443 privet_http_client_->CreateLocalPrintOperation(this);
1445 privet_local_print_operation_->SetTicket(print_ticket);
1446 privet_local_print_operation_->SetCapabilities(capabilities);
1448 scoped_refptr<base::RefCountedBytes> data;
1449 base::string16 title;
1451 if (!GetPreviewDataAndTitle(&data, &title)) {
1452 base::FundamentalValue http_code_value(-1);
1453 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1457 privet_local_print_operation_->SetJobname(base::UTF16ToUTF8(title));
1458 privet_local_print_operation_->SetPageSize(page_size);
1459 privet_local_print_operation_->SetData(data.get());
1461 Profile* profile = Profile::FromWebUI(web_ui());
1462 SigninManagerBase* signin_manager =
1463 SigninManagerFactory::GetForProfileIfExists(profile);
1465 if (signin_manager) {
1466 privet_local_print_operation_->SetUsername(
1467 signin_manager->GetAuthenticatedUsername());
1470 privet_local_print_operation_->Start();
1474 void PrintPreviewHandler::OnPrivetCapabilities(
1475 const base::DictionaryValue* capabilities) {
1476 std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1478 if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError) ||
1480 SendPrivetCapabilitiesError(name);
1484 base::DictionaryValue printer_info;
1485 const local_discovery::DeviceDescription* description =
1486 printer_lister_->GetDeviceDescription(name);
1489 SendPrivetCapabilitiesError(name);
1493 FillPrinterDescription(name, *description, true, &printer_info);
1495 web_ui()->CallJavascriptFunction(
1496 "onPrivetCapabilitiesSet",
1500 privet_capabilities_operation_.reset();
1503 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1504 const std::string& device_name) {
1505 base::StringValue name_value(device_name);
1506 web_ui()->CallJavascriptFunction(
1507 "failedToGetPrivetPrinterCapabilities",
1511 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string& device_name,
1512 const std::string& ticket,
1513 const std::string& capabilities,
1514 const gfx::Size& page_size) {
1517 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1518 base::Unretained(this),
1524 bool PrintPreviewHandler::CreatePrivetHTTP(
1525 const std::string& name,
1526 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1528 const local_discovery::DeviceDescription* device_description =
1529 printer_lister_ ? printer_lister_->GetDeviceDescription(name) : NULL;
1531 if (!device_description) {
1532 SendPrivetCapabilitiesError(name);
1536 privet_http_factory_ =
1537 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1538 service_discovery_client_.get(),
1539 Profile::FromWebUI(web_ui())->GetRequestContext());
1540 privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
1541 name, device_description->address, callback);
1542 privet_http_resolution_->Start();
1547 void PrintPreviewHandler::OnPrivetPrintingDone(
1548 const local_discovery::PrivetLocalPrintOperation* print_operation) {
1549 ClosePreviewDialog();
1552 void PrintPreviewHandler::OnPrivetPrintingError(
1553 const local_discovery::PrivetLocalPrintOperation* print_operation,
1555 base::FundamentalValue http_code_value(http_code);
1556 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1559 void PrintPreviewHandler::FillPrinterDescription(
1560 const std::string& name,
1561 const local_discovery::DeviceDescription& description,
1562 bool has_local_printing,
1563 base::DictionaryValue* printer_value) {
1564 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1566 printer_value->SetString("serviceName", name);
1567 printer_value->SetString("name", description.name);
1568 printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1569 printer_value->SetBoolean(
1571 description.id.empty() &&
1572 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos));
1573 printer_value->SetString("cloudID", description.id);
1576 #endif // defined(ENABLE_SERVICE_DISCOVERY)
1578 void PrintPreviewHandler::RegisterForMergeSession() {
1579 DCHECK(!reconcilor_);
1580 Profile* profile = Profile::FromWebUI(web_ui());
1581 if (switches::IsEnableAccountConsistency() && !profile->IsOffTheRecord()) {
1582 reconcilor_ = AccountReconcilorFactory::GetForProfile(profile);
1584 reconcilor_->AddMergeSessionObserver(this);
1588 void PrintPreviewHandler::UnregisterForMergeSession() {
1590 reconcilor_->RemoveMergeSessionObserver(this);
1593 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1594 const base::Closure& closure) {
1595 pdf_file_saved_closure_ = closure;