Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / webui / print_preview / print_preview_handler.cc
blobd80bb7a4f98fa503cdcee2e2386d17ddcdfe269d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
7 #include <ctype.h>
9 #include <map>
10 #include <string>
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/command_line.h"
16 #include "base/i18n/file_util_icu.h"
17 #include "base/i18n/number_formatting.h"
18 #include "base/json/json_reader.h"
19 #include "base/lazy_instance.h"
20 #include "base/memory/linked_ptr.h"
21 #include "base/memory/ref_counted_memory.h"
22 #include "base/metrics/histogram.h"
23 #include "base/path_service.h"
24 #include "base/prefs/pref_service.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/stringprintf.h"
27 #include "base/strings/utf_string_conversions.h"
28 #include "base/threading/thread.h"
29 #include "base/threading/thread_restrictions.h"
30 #include "base/values.h"
31 #include "chrome/browser/app_mode/app_mode_utils.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/platform_util.h"
34 #include "chrome/browser/printing/print_dialog_cloud.h"
35 #include "chrome/browser/printing/print_error_dialog.h"
36 #include "chrome/browser/printing/print_job_manager.h"
37 #include "chrome/browser/printing/print_preview_dialog_controller.h"
38 #include "chrome/browser/printing/print_view_manager.h"
39 #include "chrome/browser/printing/printer_manager_dialog.h"
40 #include "chrome/browser/profiles/profile.h"
41 #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
42 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
43 #include "chrome/browser/signin/signin_manager_factory.h"
44 #include "chrome/browser/ui/browser_finder.h"
45 #include "chrome/browser/ui/browser_tabstrip.h"
46 #include "chrome/browser/ui/chrome_select_file_policy.h"
47 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
48 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
49 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
50 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
51 #include "chrome/common/chrome_paths.h"
52 #include "chrome/common/chrome_switches.h"
53 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
54 #include "chrome/common/cloud_print/cloud_print_constants.h"
55 #include "chrome/common/crash_keys.h"
56 #include "chrome/common/pref_names.h"
57 #include "components/cloud_devices/common/cloud_device_description.h"
58 #include "components/cloud_devices/common/cloud_devices_urls.h"
59 #include "components/cloud_devices/common/printer_description.h"
60 #include "components/printing/common/print_messages.h"
61 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
62 #include "components/signin/core/browser/profile_oauth2_token_service.h"
63 #include "components/signin/core/browser/signin_manager.h"
64 #include "components/signin/core/common/profile_management_switches.h"
65 #include "content/public/browser/browser_context.h"
66 #include "content/public/browser/browser_thread.h"
67 #include "content/public/browser/navigation_controller.h"
68 #include "content/public/browser/navigation_entry.h"
69 #include "content/public/browser/render_process_host.h"
70 #include "content/public/browser/render_view_host.h"
71 #include "content/public/browser/web_contents.h"
72 #include "content/public/browser/web_ui.h"
73 #include "google_apis/gaia/oauth2_token_service.h"
74 #include "net/base/url_util.h"
75 #include "printing/backend/print_backend.h"
76 #include "printing/backend/print_backend_consts.h"
77 #include "printing/metafile.h"
78 #include "printing/pdf_metafile_skia.h"
79 #include "printing/pdf_render_settings.h"
80 #include "printing/print_settings.h"
81 #include "printing/printing_context.h"
82 #include "printing/units.h"
83 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
85 #if defined(OS_CHROMEOS)
86 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
87 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
88 #endif
90 #if defined(ENABLE_SERVICE_DISCOVERY)
91 #include "chrome/browser/local_discovery/privet_constants.h"
92 #endif
94 using content::BrowserThread;
95 using content::RenderViewHost;
96 using content::WebContents;
98 namespace {
100 enum UserActionBuckets {
101 PRINT_TO_PRINTER,
102 PRINT_TO_PDF,
103 CANCEL,
104 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
105 PREVIEW_FAILED,
106 PREVIEW_STARTED,
107 INITIATOR_CRASHED, // UNUSED
108 INITIATOR_CLOSED,
109 PRINT_WITH_CLOUD_PRINT,
110 PRINT_WITH_PRIVET,
111 PRINT_WITH_EXTENSION,
112 USERACTION_BUCKET_BOUNDARY
115 enum PrintSettingsBuckets {
116 LANDSCAPE = 0,
117 PORTRAIT,
118 COLOR,
119 BLACK_AND_WHITE,
120 COLLATE,
121 SIMPLEX,
122 DUPLEX,
123 TOTAL,
124 HEADERS_AND_FOOTERS,
125 CSS_BACKGROUND,
126 SELECTION_ONLY,
127 EXTERNAL_PDF_PREVIEW,
128 PAGE_RANGE,
129 DEFAULT_MEDIA,
130 NON_DEFAULT_MEDIA,
131 COPIES,
132 NON_DEFAULT_MARGINS,
133 PRINT_SETTINGS_BUCKET_BOUNDARY
136 void ReportUserActionHistogram(enum UserActionBuckets event) {
137 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
138 USERACTION_BUCKET_BOUNDARY);
141 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
142 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
143 PRINT_SETTINGS_BUCKET_BOUNDARY);
146 // Name of a dictionary field holding cloud print related data;
147 const char kAppState[] = "appState";
148 // Name of a dictionary field holding the initiator title.
149 const char kInitiatorTitle[] = "initiatorTitle";
150 // Name of a dictionary field holding the measurement system according to the
151 // locale.
152 const char kMeasurementSystem[] = "measurementSystem";
153 // Name of a dictionary field holding the number format according to the locale.
154 const char kNumberFormat[] = "numberFormat";
155 // Name of a dictionary field specifying whether to print automatically in
156 // kiosk mode. See http://crbug.com/31395.
157 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
158 // Dictionary field to indicate whether Chrome is running in forced app (app
159 // kiosk) mode. It's not the same as desktop Chrome kiosk (the one above).
160 const char kAppKioskMode[] = "appKioskMode";
161 // Dictionary field to store Cloud Print base URL.
162 const char kCloudPrintUrl[] = "cloudPrintUrl";
163 #if defined(OS_WIN)
164 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
165 #endif
166 // Name of a dictionary field holding the state of selection for document.
167 const char kDocumentHasSelection[] = "documentHasSelection";
169 // Id of the predefined PDF printer.
170 const char kLocalPdfPrinterId[] = "Save as PDF";
172 // Additional printer capability setting keys.
173 const char kPrinterId[] = "printerId";
174 const char kPrinterCapabilities[] = "capabilities";
176 // Get the print job settings dictionary from |args|. The caller takes
177 // ownership of the returned DictionaryValue. Returns NULL on failure.
178 base::DictionaryValue* GetSettingsDictionary(const base::ListValue* args) {
179 std::string json_str;
180 if (!args->GetString(0, &json_str)) {
181 NOTREACHED() << "Could not read JSON argument";
182 return NULL;
184 if (json_str.empty()) {
185 NOTREACHED() << "Empty print job settings";
186 return NULL;
188 scoped_ptr<base::DictionaryValue> settings(
189 static_cast<base::DictionaryValue*>(
190 base::JSONReader::DeprecatedRead(json_str)));
191 if (!settings.get() || !settings->IsType(base::Value::TYPE_DICTIONARY)) {
192 NOTREACHED() << "Print job settings must be a dictionary.";
193 return NULL;
196 if (settings->empty()) {
197 NOTREACHED() << "Print job settings dictionary is empty";
198 return NULL;
201 return settings.release();
204 // Track the popularity of print settings and report the stats.
205 void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
206 ReportPrintSettingHistogram(TOTAL);
208 const base::ListValue* page_range_array = NULL;
209 if (settings.GetList(printing::kSettingPageRange, &page_range_array) &&
210 !page_range_array->empty()) {
211 ReportPrintSettingHistogram(PAGE_RANGE);
214 const base::DictionaryValue* media_size_value = NULL;
215 if (settings.GetDictionary(printing::kSettingMediaSize, &media_size_value) &&
216 !media_size_value->empty()) {
217 bool is_default = false;
218 if (media_size_value->GetBoolean(printing::kSettingMediaSizeIsDefault,
219 &is_default) &&
220 is_default) {
221 ReportPrintSettingHistogram(DEFAULT_MEDIA);
222 } else {
223 ReportPrintSettingHistogram(NON_DEFAULT_MEDIA);
227 bool landscape = false;
228 if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
229 ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
231 int copies = 1;
232 if (settings.GetInteger(printing::kSettingCopies, &copies) && copies > 1)
233 ReportPrintSettingHistogram(COPIES);
235 bool collate = false;
236 if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
237 ReportPrintSettingHistogram(COLLATE);
239 int duplex_mode = 0;
240 if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
241 ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
243 int color_mode = 0;
244 if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
245 ReportPrintSettingHistogram(
246 printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
249 int margins_type = 0;
250 if (settings.GetInteger(printing::kSettingMarginsType, &margins_type) &&
251 margins_type != 0) {
252 ReportPrintSettingHistogram(NON_DEFAULT_MARGINS);
255 bool headers = false;
256 if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
257 headers) {
258 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
261 bool css_background = false;
262 if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
263 &css_background) && css_background) {
264 ReportPrintSettingHistogram(CSS_BACKGROUND);
267 bool selection_only = false;
268 if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
269 &selection_only) && selection_only) {
270 ReportPrintSettingHistogram(SELECTION_ONLY);
273 bool external_preview = false;
274 if (settings.GetBoolean(printing::kSettingOpenPDFInPreview,
275 &external_preview) && external_preview) {
276 ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW);
280 // Callback that stores a PDF file on disk.
281 void PrintToPdfCallback(const scoped_refptr<base::RefCountedBytes>& data,
282 const base::FilePath& path,
283 const base::Closure& pdf_file_saved_closure) {
284 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
285 printing::PdfMetafileSkia metafile;
286 metafile.InitFromData(static_cast<const void*>(data->front()), data->size());
287 base::File file(path,
288 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
289 metafile.SaveTo(&file);
290 if (!pdf_file_saved_closure.is_null())
291 pdf_file_saved_closure.Run();
294 std::string GetDefaultPrinterOnFileThread() {
295 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
297 scoped_refptr<printing::PrintBackend> print_backend(
298 printing::PrintBackend::CreateInstance(NULL));
300 std::string default_printer = print_backend->GetDefaultPrinterName();
301 VLOG(1) << "Default Printer: " << default_printer;
302 return default_printer;
305 class PrintingContextDelegate : public printing::PrintingContext::Delegate {
306 public:
307 // PrintingContext::Delegate methods.
308 gfx::NativeView GetParentView() override { return NULL; }
309 std::string GetAppLocale() override {
310 return g_browser_process->GetApplicationLocale();
314 gfx::Size GetDefaultPdfMediaSizeMicrons() {
315 PrintingContextDelegate delegate;
316 scoped_ptr<printing::PrintingContext> printing_context(
317 printing::PrintingContext::Create(&delegate));
318 if (printing::PrintingContext::OK != printing_context->UsePdfSettings() ||
319 printing_context->settings().device_units_per_inch() <= 0) {
320 return gfx::Size();
322 gfx::Size pdf_media_size = printing_context->GetPdfPaperSizeDeviceUnits();
323 float deviceMicronsPerDeviceUnit =
324 (printing::kHundrethsMMPerInch * 10.0f) /
325 printing_context->settings().device_units_per_inch();
326 return gfx::Size(pdf_media_size.width() * deviceMicronsPerDeviceUnit,
327 pdf_media_size.height() * deviceMicronsPerDeviceUnit);
330 typedef base::Callback<void(const base::DictionaryValue*)>
331 GetPdfCapabilitiesCallback;
333 scoped_ptr<base::DictionaryValue> GetPdfCapabilitiesOnFileThread(
334 const std::string& locale) {
335 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
337 cloud_devices::CloudDeviceDescription description;
338 using namespace cloud_devices::printer;
340 OrientationCapability orientation;
341 orientation.AddOption(cloud_devices::printer::PORTRAIT);
342 orientation.AddOption(cloud_devices::printer::LANDSCAPE);
343 orientation.AddDefaultOption(AUTO_ORIENTATION, true);
344 orientation.SaveTo(&description);
346 ColorCapability color;
348 Color standard_color(STANDARD_COLOR);
349 standard_color.vendor_id = base::IntToString(printing::COLOR);
350 color.AddDefaultOption(standard_color, true);
352 color.SaveTo(&description);
354 static const cloud_devices::printer::MediaType kPdfMedia[] = {
355 ISO_A4,
356 ISO_A3,
357 NA_LETTER,
358 NA_LEGAL,
359 NA_LEDGER
361 const gfx::Size default_media_size = GetDefaultPdfMediaSizeMicrons();
362 Media default_media(
363 "", "", default_media_size.width(), default_media_size.height());
364 if (!default_media.MatchBySize() ||
365 std::find(kPdfMedia,
366 kPdfMedia + arraysize(kPdfMedia),
367 default_media.type) == kPdfMedia + arraysize(kPdfMedia)) {
368 default_media = Media(locale == "en-US" ? NA_LETTER : ISO_A4);
370 MediaCapability media;
371 for (size_t i = 0; i < arraysize(kPdfMedia); ++i) {
372 Media media_option(kPdfMedia[i]);
373 media.AddDefaultOption(media_option,
374 default_media.type == media_option.type);
376 media.SaveTo(&description);
378 return scoped_ptr<base::DictionaryValue>(description.root().DeepCopy());
381 scoped_ptr<base::DictionaryValue> GetLocalPrinterCapabilitiesOnFileThread(
382 const std::string& printer_name) {
383 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
385 scoped_refptr<printing::PrintBackend> print_backend(
386 printing::PrintBackend::CreateInstance(NULL));
388 VLOG(1) << "Get printer capabilities start for " << printer_name;
389 crash_keys::ScopedPrinterInfo crash_key(
390 print_backend->GetPrinterDriverInfo(printer_name));
392 if (!print_backend->IsValidPrinter(printer_name)) {
393 LOG(WARNING) << "Invalid printer " << printer_name;
394 return scoped_ptr<base::DictionaryValue>();
397 printing::PrinterSemanticCapsAndDefaults info;
398 if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
399 LOG(WARNING) << "Failed to get capabilities for " << printer_name;
400 return scoped_ptr<base::DictionaryValue>();
403 scoped_ptr<base::DictionaryValue> description(
404 cloud_print::PrinterSemanticCapsAndDefaultsToCdd(info));
405 if (!description) {
406 LOG(WARNING) << "Failed to convert capabilities for " << printer_name;
407 return scoped_ptr<base::DictionaryValue>();
410 return description.Pass();
413 void EnumeratePrintersOnFileThread(base::ListValue* printers) {
414 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
416 scoped_refptr<printing::PrintBackend> print_backend(
417 printing::PrintBackend::CreateInstance(NULL));
419 VLOG(1) << "Enumerate printers start";
420 printing::PrinterList printer_list;
421 print_backend->EnumeratePrinters(&printer_list);
423 for (printing::PrinterList::iterator it = printer_list.begin();
424 it != printer_list.end(); ++it) {
425 base::DictionaryValue* printer_info = new base::DictionaryValue;
426 printers->Append(printer_info);
427 std::string printer_name;
428 std::string printer_description;
429 #if defined(OS_MACOSX)
430 // On Mac, |it->printer_description| specifies the printer name and
431 // |it->printer_name| specifies the device name / printer queue name.
432 printer_name = it->printer_description;
433 if (!it->options[kDriverNameTagName].empty())
434 printer_description = it->options[kDriverNameTagName];
435 #else
436 printer_name = it->printer_name;
437 printer_description = it->printer_description;
438 #endif
439 printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
440 printer_info->SetString(printing::kSettingPrinterDescription,
441 printer_description);
442 printer_info->SetString(printing::kSettingPrinterName, printer_name);
443 VLOG(1) << "Found printer " << printer_name
444 << " with device name " << it->printer_name;
446 base::DictionaryValue* options = new base::DictionaryValue;
447 printer_info->Set(printing::kSettingPrinterOptions, options);
448 for (std::map<std::string, std::string>::iterator opt = it->options.begin();
449 opt != it->options.end();
450 ++opt) {
451 options->SetString(opt->first, opt->second);
454 VLOG(1) << "Found printer " << printer_name << " with device name "
455 << it->printer_name;
457 VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
458 << " printers";
461 typedef base::Callback<void(const base::DictionaryValue*)>
462 GetPrinterCapabilitiesSuccessCallback;
463 typedef base::Callback<void(const std::string&)>
464 GetPrinterCapabilitiesFailureCallback;
466 void GetPrinterCapabilitiesOnFileThread(
467 const std::string& printer_name,
468 const std::string& locale,
469 const GetPrinterCapabilitiesSuccessCallback& success_cb,
470 const GetPrinterCapabilitiesFailureCallback& failure_cb) {
471 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
472 DCHECK(!printer_name.empty());
474 scoped_ptr<base::DictionaryValue> printer_capabilities(
475 printer_name == kLocalPdfPrinterId ?
476 GetPdfCapabilitiesOnFileThread(locale) :
477 GetLocalPrinterCapabilitiesOnFileThread(printer_name));
478 if (!printer_capabilities) {
479 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
480 base::Bind(failure_cb, printer_name));
481 return;
484 scoped_ptr<base::DictionaryValue> printer_info(new base::DictionaryValue);
485 printer_info->SetString(kPrinterId, printer_name);
486 printer_info->Set(kPrinterCapabilities, printer_capabilities.release());
488 BrowserThread::PostTask(
489 BrowserThread::UI, FROM_HERE,
490 base::Bind(success_cb, base::Owned(printer_info.release())));
493 base::LazyInstance<printing::StickySettings> g_sticky_settings =
494 LAZY_INSTANCE_INITIALIZER;
496 printing::StickySettings* GetStickySettings() {
497 return g_sticky_settings.Pointer();
500 // Returns a unique path for |path|, just like with downloads.
501 base::FilePath GetUniquePath(const base::FilePath& path) {
502 base::FilePath unique_path = path;
503 int uniquifier =
504 base::GetUniquePathNumber(path, base::FilePath::StringType());
505 if (uniquifier > 0) {
506 unique_path = unique_path.InsertBeforeExtensionASCII(
507 base::StringPrintf(" (%d)", uniquifier));
509 return unique_path;
512 } // namespace
514 class PrintPreviewHandler::AccessTokenService
515 : public OAuth2TokenService::Consumer {
516 public:
517 explicit AccessTokenService(PrintPreviewHandler* handler)
518 : OAuth2TokenService::Consumer("print_preview"),
519 handler_(handler) {
522 void RequestToken(const std::string& type) {
523 if (requests_.find(type) != requests_.end())
524 return; // Already in progress.
526 OAuth2TokenService* service = NULL;
527 std::string account_id;
528 if (type == "profile") {
529 Profile* profile = Profile::FromWebUI(handler_->web_ui());
530 if (profile) {
531 ProfileOAuth2TokenService* token_service =
532 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
533 SigninManagerBase* signin_manager =
534 SigninManagerFactory::GetInstance()->GetForProfile(profile);
535 account_id = signin_manager->GetAuthenticatedAccountId();
536 service = token_service;
538 } else if (type == "device") {
539 #if defined(OS_CHROMEOS)
540 chromeos::DeviceOAuth2TokenService* token_service =
541 chromeos::DeviceOAuth2TokenServiceFactory::Get();
542 account_id = token_service->GetRobotAccountId();
543 service = token_service;
544 #endif
547 if (service) {
548 OAuth2TokenService::ScopeSet oauth_scopes;
549 oauth_scopes.insert(cloud_devices::kCloudPrintAuthScope);
550 scoped_ptr<OAuth2TokenService::Request> request(
551 service->StartRequest(account_id, oauth_scopes, this));
552 requests_[type].reset(request.release());
553 } else {
554 handler_->SendAccessToken(type, std::string()); // Unknown type.
558 void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
559 const std::string& access_token,
560 const base::Time& expiration_time) override {
561 OnServiceResponce(request, access_token);
564 void OnGetTokenFailure(const OAuth2TokenService::Request* request,
565 const GoogleServiceAuthError& error) override {
566 OnServiceResponce(request, std::string());
569 private:
570 void OnServiceResponce(const OAuth2TokenService::Request* request,
571 const std::string& access_token) {
572 for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
573 if (i->second == request) {
574 handler_->SendAccessToken(i->first, access_token);
575 requests_.erase(i);
576 return;
579 NOTREACHED();
582 typedef std::map<std::string,
583 linked_ptr<OAuth2TokenService::Request> > Requests;
584 Requests requests_;
585 PrintPreviewHandler* handler_;
587 DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
590 PrintPreviewHandler::PrintPreviewHandler()
591 : regenerate_preview_request_count_(0),
592 manage_printers_dialog_request_count_(0),
593 manage_cloud_printers_dialog_request_count_(0),
594 reported_failed_preview_(false),
595 has_logged_printers_count_(false),
596 gaia_cookie_manager_service_(NULL),
597 weak_factory_(this) {
598 ReportUserActionHistogram(PREVIEW_STARTED);
601 PrintPreviewHandler::~PrintPreviewHandler() {
602 if (select_file_dialog_.get())
603 select_file_dialog_->ListenerDestroyed();
605 UnregisterForGaiaCookieChanges();
608 void PrintPreviewHandler::RegisterMessages() {
609 web_ui()->RegisterMessageCallback("getPrinters",
610 base::Bind(&PrintPreviewHandler::HandleGetPrinters,
611 base::Unretained(this)));
612 web_ui()->RegisterMessageCallback("getPreview",
613 base::Bind(&PrintPreviewHandler::HandleGetPreview,
614 base::Unretained(this)));
615 web_ui()->RegisterMessageCallback("print",
616 base::Bind(&PrintPreviewHandler::HandlePrint,
617 base::Unretained(this)));
618 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
619 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
620 base::Unretained(this)));
621 #if defined(ENABLE_BASIC_PRINTING)
622 web_ui()->RegisterMessageCallback("showSystemDialog",
623 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
624 base::Unretained(this)));
625 #endif // ENABLE_BASIC_PRINTING
626 web_ui()->RegisterMessageCallback("signIn",
627 base::Bind(&PrintPreviewHandler::HandleSignin,
628 base::Unretained(this)));
629 web_ui()->RegisterMessageCallback("getAccessToken",
630 base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
631 base::Unretained(this)));
632 web_ui()->RegisterMessageCallback("manageCloudPrinters",
633 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
634 base::Unretained(this)));
635 web_ui()->RegisterMessageCallback("manageLocalPrinters",
636 base::Bind(&PrintPreviewHandler::HandleManagePrinters,
637 base::Unretained(this)));
638 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
639 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
640 base::Unretained(this)));
641 web_ui()->RegisterMessageCallback("hidePreview",
642 base::Bind(&PrintPreviewHandler::HandleHidePreview,
643 base::Unretained(this)));
644 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
645 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
646 base::Unretained(this)));
647 web_ui()->RegisterMessageCallback("saveAppState",
648 base::Bind(&PrintPreviewHandler::HandleSaveAppState,
649 base::Unretained(this)));
650 web_ui()->RegisterMessageCallback("getInitialSettings",
651 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
652 base::Unretained(this)));
653 web_ui()->RegisterMessageCallback("forceOpenNewTab",
654 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
655 base::Unretained(this)));
656 web_ui()->RegisterMessageCallback("getPrivetPrinters",
657 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
658 base::Unretained(this)));
659 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
660 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
661 base::Unretained(this)));
662 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
663 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
664 base::Unretained(this)));
665 web_ui()->RegisterMessageCallback(
666 "getExtensionPrinters",
667 base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinters,
668 base::Unretained(this)));
669 web_ui()->RegisterMessageCallback(
670 "getExtensionPrinterCapabilities",
671 base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinterCapabilities,
672 base::Unretained(this)));
673 RegisterForGaiaCookieChanges();
676 bool PrintPreviewHandler::PrivetPrintingEnabled() {
677 #if defined(ENABLE_SERVICE_DISCOVERY)
678 return true;
679 #else
680 return false;
681 #endif
684 WebContents* PrintPreviewHandler::preview_web_contents() const {
685 return web_ui()->GetWebContents();
688 PrintPreviewUI* PrintPreviewHandler::print_preview_ui() const {
689 return static_cast<PrintPreviewUI*>(web_ui()->GetController());
692 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
693 base::ListValue* results = new base::ListValue;
694 BrowserThread::PostTaskAndReply(
695 BrowserThread::FILE, FROM_HERE,
696 base::Bind(&EnumeratePrintersOnFileThread,
697 base::Unretained(results)),
698 base::Bind(&PrintPreviewHandler::SetupPrinterList,
699 weak_factory_.GetWeakPtr(),
700 base::Owned(results)));
703 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
704 if (!PrivetPrintingEnabled())
705 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
706 #if defined(ENABLE_SERVICE_DISCOVERY)
707 using local_discovery::ServiceDiscoverySharedClient;
708 scoped_refptr<ServiceDiscoverySharedClient> service_discovery =
709 ServiceDiscoverySharedClient::GetInstance();
710 StartPrivetLister(service_discovery);
711 #endif // ENABLE_SERVICE_DISCOVERY
714 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
715 const base::ListValue* args) {
716 #if defined(ENABLE_SERVICE_DISCOVERY)
717 if (PrivetPrintingEnabled() && printer_lister_) {
718 printer_lister_->Stop();
720 #endif
723 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
724 const base::ListValue* args) {
725 #if defined(ENABLE_SERVICE_DISCOVERY)
726 std::string name;
727 bool success = args->GetString(0, &name);
728 DCHECK(success);
730 CreatePrivetHTTP(
731 name,
732 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
733 base::Unretained(this)));
734 #endif
737 void PrintPreviewHandler::HandleGetExtensionPrinters(
738 const base::ListValue* args) {
739 EnsureExtensionPrinterHandlerSet();
740 // Make sure all in progress requests are canceled before new printer search
741 // starts.
742 extension_printer_handler_->Reset();
743 extension_printer_handler_->StartGetPrinters(base::Bind(
744 &PrintPreviewHandler::OnGotPrintersForExtension, base::Unretained(this)));
747 void PrintPreviewHandler::HandleGetExtensionPrinterCapabilities(
748 const base::ListValue* args) {
749 std::string printer_id;
750 bool ok = args->GetString(0, &printer_id);
751 DCHECK(ok);
753 EnsureExtensionPrinterHandlerSet();
754 extension_printer_handler_->StartGetCapability(
755 printer_id,
756 base::Bind(&PrintPreviewHandler::OnGotExtensionPrinterCapabilities,
757 base::Unretained(this)));
760 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
761 DCHECK_EQ(3U, args->GetSize());
762 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
763 if (!settings.get())
764 return;
765 int request_id = -1;
766 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
767 return;
769 print_preview_ui()->OnPrintPreviewRequest(request_id);
770 // Add an additional key in order to identify |print_preview_ui| later on
771 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
772 // thread.
773 settings->SetInteger(printing::kPreviewUIID,
774 print_preview_ui()->GetIDForPrintPreviewUI());
776 // Increment request count.
777 ++regenerate_preview_request_count_;
779 WebContents* initiator = GetInitiator();
780 if (!initiator) {
781 ReportUserActionHistogram(INITIATOR_CLOSED);
782 print_preview_ui()->OnClosePrintPreviewDialog();
783 return;
786 // Retrieve the page title and url and send it to the renderer process if
787 // headers and footers are to be displayed.
788 bool display_header_footer = false;
789 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
790 &display_header_footer)) {
791 NOTREACHED();
793 if (display_header_footer) {
794 settings->SetString(printing::kSettingHeaderFooterTitle,
795 initiator->GetTitle());
796 std::string url;
797 content::NavigationEntry* entry =
798 initiator->GetController().GetLastCommittedEntry();
799 if (entry)
800 url = entry->GetVirtualURL().spec();
801 settings->SetString(printing::kSettingHeaderFooterURL, url);
804 bool generate_draft_data = false;
805 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
806 &generate_draft_data);
807 DCHECK(success);
809 if (!generate_draft_data) {
810 double draft_page_count_double = -1;
811 success = args->GetDouble(1, &draft_page_count_double);
812 DCHECK(success);
813 int draft_page_count = static_cast<int>(draft_page_count_double);
815 bool preview_modifiable = false;
816 success = args->GetBoolean(2, &preview_modifiable);
817 DCHECK(success);
819 if (draft_page_count != -1 && preview_modifiable &&
820 print_preview_ui()->GetAvailableDraftPageCount() != draft_page_count) {
821 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
825 VLOG(1) << "Print preview request start";
826 RenderViewHost* rvh = initiator->GetRenderViewHost();
827 rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
830 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
831 ReportStats();
833 // Record the number of times the user requests to regenerate preview data
834 // before printing.
835 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
836 regenerate_preview_request_count_);
838 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
839 if (!settings.get())
840 return;
842 ReportPrintSettingsStats(*settings);
844 // Never try to add headers/footers here. It's already in the generated PDF.
845 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
847 bool print_to_pdf = false;
848 bool is_cloud_printer = false;
849 bool print_with_privet = false;
850 bool print_with_extension = false;
852 bool open_pdf_in_preview = false;
853 #if defined(OS_MACOSX)
854 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
855 #endif
857 if (!open_pdf_in_preview) {
858 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
859 settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
860 settings->GetBoolean(printing::kSettingPrintWithExtension,
861 &print_with_extension);
862 is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
865 int page_count = 0;
866 settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
868 if (print_to_pdf) {
869 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
870 ReportUserActionHistogram(PRINT_TO_PDF);
871 PrintToPdf();
872 return;
875 #if defined(ENABLE_SERVICE_DISCOVERY)
876 if (print_with_privet && PrivetPrintingEnabled()) {
877 std::string printer_name;
878 std::string print_ticket;
879 std::string capabilities;
880 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
881 ReportUserActionHistogram(PRINT_WITH_PRIVET);
883 int width = 0;
884 int height = 0;
885 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
886 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
887 !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
888 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
889 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
890 width <= 0 || height <= 0) {
891 NOTREACHED();
892 base::FundamentalValue http_code_value(-1);
893 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
894 return;
897 PrintToPrivetPrinter(
898 printer_name, print_ticket, capabilities, gfx::Size(width, height));
899 return;
901 #endif
903 if (print_with_extension) {
904 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithExtension",
905 page_count);
906 ReportUserActionHistogram(PRINT_WITH_EXTENSION);
908 std::string destination_id;
909 std::string print_ticket;
910 std::string capabilities;
911 int width = 0;
912 int height = 0;
913 if (!settings->GetString(printing::kSettingDeviceName, &destination_id) ||
914 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
915 !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
916 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
917 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
918 width <= 0 || height <= 0) {
919 NOTREACHED();
920 OnExtensionPrintResult(false, "FAILED");
921 return;
924 base::string16 title;
925 scoped_refptr<base::RefCountedBytes> data;
926 if (!GetPreviewDataAndTitle(&data, &title)) {
927 LOG(ERROR) << "Nothing to print; no preview available.";
928 OnExtensionPrintResult(false, "NO_DATA");
929 return;
932 EnsureExtensionPrinterHandlerSet();
933 extension_printer_handler_->StartPrint(
934 destination_id, capabilities, title, print_ticket,
935 gfx::Size(width, height), data,
936 base::Bind(&PrintPreviewHandler::OnExtensionPrintResult,
937 base::Unretained(this)));
938 return;
941 scoped_refptr<base::RefCountedBytes> data;
942 base::string16 title;
943 if (!GetPreviewDataAndTitle(&data, &title)) {
944 // Nothing to print, no preview available.
945 return;
948 if (is_cloud_printer) {
949 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
950 page_count);
951 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
952 SendCloudPrintJob(data.get());
953 } else {
954 bool system_dialog = false;
955 settings->GetBoolean(printing::kSettingShowSystemDialog, &system_dialog);
956 if (system_dialog) {
957 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count);
958 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
959 } else {
960 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
961 ReportUserActionHistogram(PRINT_TO_PRINTER);
964 // This tries to activate the initiator as well, so do not clear the
965 // association with the initiator yet.
966 print_preview_ui()->OnHidePreviewDialog();
968 // Do this so the initiator can open a new print preview dialog, while the
969 // current print preview dialog is still handling its print job.
970 WebContents* initiator = GetInitiator();
971 if (initiator) {
972 // Save initiator IDs. |PrintingMessageFilter::OnUpdatePrintSettings|
973 // would be called when initiator info is cleared.
974 settings->SetInteger(printing::kPreviewInitiatorHostId,
975 initiator->GetRenderProcessHost()->GetID());
976 settings->SetInteger(printing::kPreviewInitiatorRoutingId,
977 initiator->GetRoutingID());
980 ClearInitiatorDetails();
982 // The PDF being printed contains only the pages that the user selected,
983 // so ignore the page range and print all pages.
984 settings->Remove(printing::kSettingPageRange, NULL);
985 // Reset selection only flag for the same reason.
986 settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
988 // Set ID to know whether printing is for preview.
989 settings->SetInteger(printing::kPreviewUIID,
990 print_preview_ui()->GetIDForPrintPreviewUI());
991 RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
992 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
993 *settings));
995 // For all other cases above, the preview dialog will stay open until the
996 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
997 // called. In the case below, since the preview dialog will be hidden and
998 // not closed, we need to make this call.
999 if (initiator) {
1000 printing::PrintViewManager* print_view_manager =
1001 printing::PrintViewManager::FromWebContents(initiator);
1002 print_view_manager->PrintPreviewDone();
1007 void PrintPreviewHandler::PrintToPdf() {
1008 if (!print_to_pdf_path_.empty()) {
1009 // User has already selected a path, no need to show the dialog again.
1010 PostPrintToPdfTask();
1011 } else if (!select_file_dialog_.get() ||
1012 !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
1013 preview_web_contents()->GetNativeView()))) {
1014 // Pre-populating select file dialog with print job title.
1015 base::string16 print_job_title_utf16 =
1016 print_preview_ui()->initiator_title();
1018 #if defined(OS_WIN)
1019 base::FilePath::StringType print_job_title(print_job_title_utf16);
1020 #elif defined(OS_POSIX)
1021 base::FilePath::StringType print_job_title =
1022 base::UTF16ToUTF8(print_job_title_utf16);
1023 #endif
1025 base::i18n::ReplaceIllegalCharactersInPath(&print_job_title, '_');
1026 base::FilePath default_filename(print_job_title);
1027 default_filename =
1028 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
1030 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1031 bool prompt_user = !cmdline->HasSwitch(switches::kKioskModePrinting);
1032 SelectFile(default_filename, prompt_user);
1036 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
1037 print_preview_ui()->OnHidePreviewDialog();
1040 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
1041 const base::ListValue* /*args*/) {
1042 WebContents* initiator = GetInitiator();
1043 if (initiator)
1044 ClearInitiatorDetails();
1045 chrome::ShowPrintErrorDialog();
1048 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
1049 std::string data_to_save;
1050 printing::StickySettings* sticky_settings = GetStickySettings();
1051 if (args->GetString(0, &data_to_save) && !data_to_save.empty())
1052 sticky_settings->StoreAppState(data_to_save);
1053 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1054 preview_web_contents()->GetBrowserContext())->GetPrefs());
1057 void PrintPreviewHandler::HandleGetPrinterCapabilities(
1058 const base::ListValue* args) {
1059 std::string printer_name;
1060 bool ret = args->GetString(0, &printer_name);
1061 if (!ret || printer_name.empty())
1062 return;
1064 GetPrinterCapabilitiesSuccessCallback success_cb =
1065 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
1066 weak_factory_.GetWeakPtr());
1067 GetPrinterCapabilitiesFailureCallback failure_cb =
1068 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
1069 weak_factory_.GetWeakPtr());
1070 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1071 base::Bind(&GetPrinterCapabilitiesOnFileThread,
1072 printer_name,
1073 g_browser_process->GetApplicationLocale(),
1074 success_cb, failure_cb));
1077 void PrintPreviewHandler::OnSigninComplete() {
1078 if (print_preview_ui())
1079 print_preview_ui()->OnReloadPrintersList();
1082 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
1083 bool add_account = false;
1084 bool success = args->GetBoolean(0, &add_account);
1085 DCHECK(success);
1087 Profile* profile = Profile::FromBrowserContext(
1088 preview_web_contents()->GetBrowserContext());
1089 chrome::ScopedTabbedBrowserDisplayer displayer(
1090 profile, chrome::GetActiveDesktop());
1091 print_dialog_cloud::CreateCloudPrintSigninTab(
1092 displayer.browser(),
1093 add_account,
1094 base::Bind(&PrintPreviewHandler::OnSigninComplete,
1095 weak_factory_.GetWeakPtr()));
1098 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
1099 std::string type;
1100 if (!args->GetString(0, &type))
1101 return;
1102 if (!token_service_)
1103 token_service_.reset(new AccessTokenService(this));
1104 token_service_->RequestToken(type);
1107 void PrintPreviewHandler::HandleManageCloudPrint(
1108 const base::ListValue* args) {
1109 ++manage_cloud_printers_dialog_request_count_;
1110 GURL manage_url(cloud_devices::GetCloudPrintRelativeURL("manage.html"));
1111 std::string user;
1112 if (!args->GetString(0, &user))
1113 return;
1114 if (!user.empty())
1115 manage_url = net::AppendQueryParameter(manage_url, "user", user);
1116 preview_web_contents()->OpenURL(content::OpenURLParams(
1117 manage_url,
1118 content::Referrer(),
1119 NEW_FOREGROUND_TAB,
1120 ui::PAGE_TRANSITION_LINK,
1121 false));
1124 #if defined(ENABLE_BASIC_PRINTING)
1125 void PrintPreviewHandler::HandleShowSystemDialog(
1126 const base::ListValue* /*args*/) {
1127 ReportStats();
1128 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1130 WebContents* initiator = GetInitiator();
1131 if (!initiator)
1132 return;
1134 printing::PrintViewManager* print_view_manager =
1135 printing::PrintViewManager::FromWebContents(initiator);
1136 print_view_manager->set_observer(this);
1137 print_view_manager->PrintForSystemDialogNow();
1139 // Cancel the pending preview request if exists.
1140 print_preview_ui()->OnCancelPendingPreviewRequest();
1142 #endif // ENABLE_BASIC_PRINTING
1144 void PrintPreviewHandler::HandleManagePrinters(
1145 const base::ListValue* /*args*/) {
1146 ++manage_printers_dialog_request_count_;
1147 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1150 void PrintPreviewHandler::HandleClosePreviewDialog(
1151 const base::ListValue* /*args*/) {
1152 ReportStats();
1153 ReportUserActionHistogram(CANCEL);
1155 // Record the number of times the user requests to regenerate preview data
1156 // before cancelling.
1157 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1158 regenerate_preview_request_count_);
1161 void PrintPreviewHandler::ReportStats() {
1162 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1163 manage_printers_dialog_request_count_);
1164 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1165 manage_cloud_printers_dialog_request_count_);
1168 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1169 base::DictionaryValue* settings) {
1171 // Getting the measurement system based on the locale.
1172 UErrorCode errorCode = U_ZERO_ERROR;
1173 const char* locale = g_browser_process->GetApplicationLocale().c_str();
1174 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1175 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1176 system = UMS_SI;
1178 // Getting the number formatting based on the locale and writing to
1179 // dictionary.
1180 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1181 settings->SetInteger(kMeasurementSystem, system);
1184 void PrintPreviewHandler::HandleGetInitialSettings(
1185 const base::ListValue* /*args*/) {
1186 // Send before SendInitialSettings to allow cloud printer auto select.
1187 SendCloudPrintEnabled();
1188 BrowserThread::PostTaskAndReplyWithResult(
1189 BrowserThread::FILE, FROM_HERE,
1190 base::Bind(&GetDefaultPrinterOnFileThread),
1191 base::Bind(&PrintPreviewHandler::SendInitialSettings,
1192 weak_factory_.GetWeakPtr()));
1195 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1196 std::string url;
1197 if (!args->GetString(0, &url))
1198 return;
1199 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1200 if (!browser)
1201 return;
1202 chrome::AddSelectedTabWithURL(browser,
1203 GURL(url),
1204 ui::PAGE_TRANSITION_LINK);
1207 void PrintPreviewHandler::SendInitialSettings(
1208 const std::string& default_printer) {
1209 base::DictionaryValue initial_settings;
1210 initial_settings.SetString(kInitiatorTitle,
1211 print_preview_ui()->initiator_title());
1212 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1213 print_preview_ui()->source_is_modifiable());
1214 initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1215 initial_settings.SetBoolean(kDocumentHasSelection,
1216 print_preview_ui()->source_has_selection());
1217 initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1218 print_preview_ui()->print_selection_only());
1219 printing::StickySettings* sticky_settings = GetStickySettings();
1220 sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1221 preview_web_contents()->GetBrowserContext())->GetPrefs());
1222 if (sticky_settings->printer_app_state()) {
1223 initial_settings.SetString(kAppState,
1224 *sticky_settings->printer_app_state());
1227 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1228 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1229 cmdline->HasSwitch(switches::kKioskModePrinting));
1230 initial_settings.SetBoolean(kAppKioskMode,
1231 chrome::IsRunningInForcedAppMode());
1232 #if defined(OS_WIN)
1233 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1234 // so will cause the browser to appear hung, so we don't show the link in
1235 // metro.
1236 bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1237 initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1238 #endif
1240 if (print_preview_ui()->source_is_modifiable())
1241 GetNumberFormatAndMeasurementSystem(&initial_settings);
1242 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1245 void PrintPreviewHandler::ClosePreviewDialog() {
1246 print_preview_ui()->OnClosePrintPreviewDialog();
1249 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1250 const std::string& access_token) {
1251 VLOG(1) << "Get getAccessToken finished";
1252 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1253 base::StringValue(type),
1254 base::StringValue(access_token));
1257 void PrintPreviewHandler::SendPrinterCapabilities(
1258 const base::DictionaryValue* settings_info) {
1259 VLOG(1) << "Get printer capabilities finished";
1260 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1261 *settings_info);
1264 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1265 const std::string& printer_name) {
1266 VLOG(1) << "Get printer capabilities failed";
1267 base::StringValue printer_name_value(printer_name);
1268 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1269 printer_name_value);
1272 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1273 if (!has_logged_printers_count_) {
1274 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1275 has_logged_printers_count_ = true;
1278 web_ui()->CallJavascriptFunction("setPrinters", *printers);
1281 void PrintPreviewHandler::SendCloudPrintEnabled() {
1282 Profile* profile = Profile::FromBrowserContext(
1283 preview_web_contents()->GetBrowserContext());
1284 PrefService* prefs = profile->GetPrefs();
1285 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1286 base::DictionaryValue settings;
1287 settings.SetString(kCloudPrintUrl,
1288 GURL(cloud_devices::GetCloudPrintURL()).spec());
1289 settings.SetBoolean(kAppKioskMode, chrome::IsRunningInForcedAppMode());
1290 web_ui()->CallJavascriptFunction("setUseCloudPrint", settings);
1294 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1295 // BASE64 encode the job data.
1296 std::string raw_data(reinterpret_cast<const char*>(data->front()),
1297 data->size());
1298 std::string base64_data;
1299 base::Base64Encode(raw_data, &base64_data);
1300 base::StringValue data_value(base64_data);
1302 web_ui()->CallJavascriptFunction("printToCloud", data_value);
1305 WebContents* PrintPreviewHandler::GetInitiator() const {
1306 printing::PrintPreviewDialogController* dialog_controller =
1307 printing::PrintPreviewDialogController::GetInstance();
1308 if (!dialog_controller)
1309 return NULL;
1310 return dialog_controller->GetInitiator(preview_web_contents());
1313 void PrintPreviewHandler::OnPrintDialogShown() {
1314 ClosePreviewDialog();
1317 void PrintPreviewHandler::OnAddAccountToCookieCompleted(
1318 const std::string& account_id,
1319 const GoogleServiceAuthError& error) {
1320 OnSigninComplete();
1323 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename,
1324 bool prompt_user) {
1325 if (prompt_user) {
1326 ChromeSelectFilePolicy policy(GetInitiator());
1327 if (!policy.CanOpenSelectFileDialog()) {
1328 policy.SelectFileDenied();
1329 return ClosePreviewDialog();
1333 // Initializing |save_path_| if it is not already initialized.
1334 printing::StickySettings* sticky_settings = GetStickySettings();
1335 if (!sticky_settings->save_path()) {
1336 // Allowing IO operation temporarily. It is ok to do so here because
1337 // the select file dialog performs IO anyway in order to display the
1338 // folders and also it is modal.
1339 base::ThreadRestrictions::ScopedAllowIO allow_io;
1340 base::FilePath file_path;
1341 PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1342 sticky_settings->StoreSavePath(file_path);
1343 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1344 preview_web_contents()->GetBrowserContext())->GetPrefs());
1347 // Handle the no prompting case. Like the dialog prompt, this function
1348 // returns and eventually FileSelected() gets called.
1349 if (!prompt_user) {
1350 base::PostTaskAndReplyWithResult(
1351 BrowserThread::GetBlockingPool(),
1352 FROM_HERE,
1353 base::Bind(&GetUniquePath,
1354 sticky_settings->save_path()->Append(default_filename)),
1355 base::Bind(&PrintPreviewHandler::OnGotUniqueFileName,
1356 weak_factory_.GetWeakPtr()));
1357 return;
1360 // Otherwise prompt the user.
1361 ui::SelectFileDialog::FileTypeInfo file_type_info;
1362 file_type_info.extensions.resize(1);
1363 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1365 select_file_dialog_ =
1366 ui::SelectFileDialog::Create(this, nullptr /*policy already checked*/);
1367 select_file_dialog_->SelectFile(
1368 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1369 base::string16(),
1370 sticky_settings->save_path()->Append(default_filename),
1371 &file_type_info,
1373 base::FilePath::StringType(),
1374 platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1375 NULL);
1378 void PrintPreviewHandler::OnGotUniqueFileName(const base::FilePath& path) {
1379 FileSelected(path, 0, nullptr);
1382 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1383 WebContents* initiator = GetInitiator();
1384 if (!initiator)
1385 return;
1387 printing::PrintViewManager* print_view_manager =
1388 printing::PrintViewManager::FromWebContents(initiator);
1389 print_view_manager->set_observer(NULL);
1392 void PrintPreviewHandler::OnPrintPreviewFailed() {
1393 if (reported_failed_preview_)
1394 return;
1395 reported_failed_preview_ = true;
1396 ReportUserActionHistogram(PREVIEW_FAILED);
1399 #if defined(ENABLE_BASIC_PRINTING)
1400 void PrintPreviewHandler::ShowSystemDialog() {
1401 HandleShowSystemDialog(NULL);
1403 #endif // ENABLE_BASIC_PRINTING
1405 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1406 int /* index */,
1407 void* /* params */) {
1408 // Updating |save_path_| to the newly selected folder.
1409 printing::StickySettings* sticky_settings = GetStickySettings();
1410 sticky_settings->StoreSavePath(path.DirName());
1411 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1412 preview_web_contents()->GetBrowserContext())->GetPrefs());
1413 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1414 print_to_pdf_path_ = path;
1415 PostPrintToPdfTask();
1418 void PrintPreviewHandler::PostPrintToPdfTask() {
1419 scoped_refptr<base::RefCountedBytes> data;
1420 base::string16 title;
1421 if (!GetPreviewDataAndTitle(&data, &title)) {
1422 NOTREACHED() << "Preview data was checked before file dialog.";
1423 return;
1425 BrowserThread::PostTask(BrowserThread::FILE,
1426 FROM_HERE,
1427 base::Bind(&PrintToPdfCallback,
1428 data,
1429 print_to_pdf_path_,
1430 pdf_file_saved_closure_));
1431 print_to_pdf_path_ = base::FilePath();
1432 ClosePreviewDialog();
1435 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1436 print_preview_ui()->OnFileSelectionCancelled();
1439 void PrintPreviewHandler::ClearInitiatorDetails() {
1440 WebContents* initiator = GetInitiator();
1441 if (!initiator)
1442 return;
1444 // We no longer require the initiator details. Remove those details associated
1445 // with the preview dialog to allow the initiator to create another preview
1446 // dialog.
1447 printing::PrintPreviewDialogController* dialog_controller =
1448 printing::PrintPreviewDialogController::GetInstance();
1449 if (dialog_controller)
1450 dialog_controller->EraseInitiatorInfo(preview_web_contents());
1453 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1454 scoped_refptr<base::RefCountedBytes>* data,
1455 base::string16* title) const {
1456 scoped_refptr<base::RefCountedBytes> tmp_data;
1457 print_preview_ui()->GetPrintPreviewDataForIndex(
1458 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1460 if (!tmp_data.get()) {
1461 // Nothing to print, no preview available.
1462 return false;
1464 DCHECK(tmp_data->size() && tmp_data->front());
1466 *data = tmp_data;
1467 *title = print_preview_ui()->initiator_title();
1468 return true;
1471 #if defined(ENABLE_SERVICE_DISCOVERY)
1473 void PrintPreviewHandler::StartPrivetLister(const scoped_refptr<
1474 local_discovery::ServiceDiscoverySharedClient>& client) {
1475 if (!PrivetPrintingEnabled())
1476 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1478 Profile* profile = Profile::FromWebUI(web_ui());
1479 DCHECK(!service_discovery_client_.get() ||
1480 service_discovery_client_.get() == client.get());
1481 service_discovery_client_ = client;
1482 printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
1483 service_discovery_client_.get(), profile->GetRequestContext(), this));
1484 printer_lister_->Start();
1487 void PrintPreviewHandler::LocalPrinterChanged(
1488 bool added,
1489 const std::string& name,
1490 bool has_local_printing,
1491 const local_discovery::DeviceDescription& description) {
1492 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1493 if (has_local_printing ||
1494 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) {
1495 base::DictionaryValue info;
1496 FillPrinterDescription(name, description, has_local_printing, &info);
1497 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1501 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1504 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1507 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1508 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1509 if (!PrivetUpdateClient(http_client.Pass()))
1510 return;
1512 privet_capabilities_operation_ =
1513 privet_http_client_->CreateCapabilitiesOperation(
1514 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1515 base::Unretained(this)));
1516 privet_capabilities_operation_->Start();
1519 bool PrintPreviewHandler::PrivetUpdateClient(
1520 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1521 if (!http_client) {
1522 SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1523 privet_http_resolution_.reset();
1524 return false;
1527 privet_local_print_operation_.reset();
1528 privet_capabilities_operation_.reset();
1529 privet_http_client_ =
1530 local_discovery::PrivetV1HTTPClient::CreateDefault(http_client.Pass());
1532 privet_http_resolution_.reset();
1534 return true;
1537 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1538 std::string print_ticket,
1539 std::string capabilities,
1540 gfx::Size page_size,
1541 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1542 if (!PrivetUpdateClient(http_client.Pass()))
1543 return;
1545 StartPrivetLocalPrint(print_ticket, capabilities, page_size);
1548 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string& print_ticket,
1549 const std::string& capabilities,
1550 const gfx::Size& page_size) {
1551 privet_local_print_operation_ =
1552 privet_http_client_->CreateLocalPrintOperation(this);
1554 privet_local_print_operation_->SetTicket(print_ticket);
1555 privet_local_print_operation_->SetCapabilities(capabilities);
1557 scoped_refptr<base::RefCountedBytes> data;
1558 base::string16 title;
1560 if (!GetPreviewDataAndTitle(&data, &title)) {
1561 base::FundamentalValue http_code_value(-1);
1562 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1563 return;
1566 privet_local_print_operation_->SetJobname(base::UTF16ToUTF8(title));
1567 privet_local_print_operation_->SetPageSize(page_size);
1568 privet_local_print_operation_->SetData(data.get());
1570 Profile* profile = Profile::FromWebUI(web_ui());
1571 SigninManagerBase* signin_manager =
1572 SigninManagerFactory::GetForProfileIfExists(profile);
1574 if (signin_manager) {
1575 privet_local_print_operation_->SetUsername(
1576 signin_manager->GetAuthenticatedUsername());
1579 privet_local_print_operation_->Start();
1583 void PrintPreviewHandler::OnPrivetCapabilities(
1584 const base::DictionaryValue* capabilities) {
1585 std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1587 if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError) ||
1588 !printer_lister_) {
1589 SendPrivetCapabilitiesError(name);
1590 return;
1593 base::DictionaryValue printer_info;
1594 const local_discovery::DeviceDescription* description =
1595 printer_lister_->GetDeviceDescription(name);
1597 if (!description) {
1598 SendPrivetCapabilitiesError(name);
1599 return;
1602 FillPrinterDescription(name, *description, true, &printer_info);
1604 web_ui()->CallJavascriptFunction(
1605 "onPrivetCapabilitiesSet",
1606 printer_info,
1607 *capabilities);
1609 privet_capabilities_operation_.reset();
1612 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1613 const std::string& device_name) {
1614 base::StringValue name_value(device_name);
1615 web_ui()->CallJavascriptFunction(
1616 "failedToGetPrivetPrinterCapabilities",
1617 name_value);
1620 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string& device_name,
1621 const std::string& ticket,
1622 const std::string& capabilities,
1623 const gfx::Size& page_size) {
1624 CreatePrivetHTTP(
1625 device_name,
1626 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1627 base::Unretained(this),
1628 ticket,
1629 capabilities,
1630 page_size));
1633 bool PrintPreviewHandler::CreatePrivetHTTP(
1634 const std::string& name,
1635 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1636 callback) {
1637 const local_discovery::DeviceDescription* device_description =
1638 printer_lister_ ? printer_lister_->GetDeviceDescription(name) : NULL;
1640 if (!device_description) {
1641 SendPrivetCapabilitiesError(name);
1642 return false;
1645 privet_http_factory_ =
1646 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1647 Profile::FromWebUI(web_ui())->GetRequestContext());
1648 privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(name);
1649 privet_http_resolution_->Start(device_description->address, callback);
1651 return true;
1654 void PrintPreviewHandler::OnPrivetPrintingDone(
1655 const local_discovery::PrivetLocalPrintOperation* print_operation) {
1656 ClosePreviewDialog();
1659 void PrintPreviewHandler::OnPrivetPrintingError(
1660 const local_discovery::PrivetLocalPrintOperation* print_operation,
1661 int http_code) {
1662 base::FundamentalValue http_code_value(http_code);
1663 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1666 void PrintPreviewHandler::FillPrinterDescription(
1667 const std::string& name,
1668 const local_discovery::DeviceDescription& description,
1669 bool has_local_printing,
1670 base::DictionaryValue* printer_value) {
1671 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1673 printer_value->SetString("serviceName", name);
1674 printer_value->SetString("name", description.name);
1675 printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1676 printer_value->SetBoolean(
1677 "isUnregistered",
1678 description.id.empty() &&
1679 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos));
1680 printer_value->SetString("cloudID", description.id);
1683 #endif // defined(ENABLE_SERVICE_DISCOVERY)
1685 void PrintPreviewHandler::EnsureExtensionPrinterHandlerSet() {
1686 if (extension_printer_handler_)
1687 return;
1689 extension_printer_handler_ =
1690 PrinterHandler::CreateForExtensionPrinters(Profile::FromWebUI(web_ui()));
1693 void PrintPreviewHandler::OnGotPrintersForExtension(
1694 const base::ListValue& printers,
1695 bool done) {
1696 web_ui()->CallJavascriptFunction("onExtensionPrintersAdded", printers,
1697 base::FundamentalValue(done));
1700 void PrintPreviewHandler::OnGotExtensionPrinterCapabilities(
1701 const std::string& printer_id,
1702 const base::DictionaryValue& capabilities) {
1703 if (capabilities.empty()) {
1704 web_ui()->CallJavascriptFunction("failedToGetExtensionPrinterCapabilities",
1705 base::StringValue(printer_id));
1706 return;
1709 web_ui()->CallJavascriptFunction("onExtensionCapabilitiesSet",
1710 base::StringValue(printer_id), capabilities);
1713 void PrintPreviewHandler::OnExtensionPrintResult(bool success,
1714 const std::string& status) {
1715 if (success) {
1716 ClosePreviewDialog();
1717 return;
1720 // TODO(tbarzic): This function works for extension printers case too, but it
1721 // should be renamed to something more generic.
1722 web_ui()->CallJavascriptFunction("onPrivetPrintFailed",
1723 base::StringValue(status));
1726 void PrintPreviewHandler::RegisterForGaiaCookieChanges() {
1727 DCHECK(!gaia_cookie_manager_service_);
1728 Profile* profile = Profile::FromWebUI(web_ui());
1729 if (switches::IsEnableAccountConsistency() && !profile->IsOffTheRecord()) {
1730 gaia_cookie_manager_service_ =
1731 GaiaCookieManagerServiceFactory::GetForProfile(profile);
1732 if (gaia_cookie_manager_service_)
1733 gaia_cookie_manager_service_->AddObserver(this);
1737 void PrintPreviewHandler::UnregisterForGaiaCookieChanges() {
1738 if (gaia_cookie_manager_service_)
1739 gaia_cookie_manager_service_->RemoveObserver(this);
1742 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1743 const base::Closure& closure) {
1744 pdf_file_saved_closure_ = closure;