Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / webui / print_preview / print_preview_handler.cc
blobacd2fe5ddea5d155881f8a0b34d4c4926e64ab54
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/dom_distiller/tab_utils.h"
34 #include "chrome/browser/platform_util.h"
35 #include "chrome/browser/printing/print_dialog_cloud.h"
36 #include "chrome/browser/printing/print_error_dialog.h"
37 #include "chrome/browser/printing/print_job_manager.h"
38 #include "chrome/browser/printing/print_preview_dialog_controller.h"
39 #include "chrome/browser/printing/print_view_manager.h"
40 #include "chrome/browser/printing/printer_manager_dialog.h"
41 #include "chrome/browser/profiles/profile.h"
42 #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
43 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
44 #include "chrome/browser/signin/signin_manager_factory.h"
45 #include "chrome/browser/ui/browser_finder.h"
46 #include "chrome/browser/ui/browser_tabstrip.h"
47 #include "chrome/browser/ui/chrome_select_file_policy.h"
48 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
49 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
50 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
51 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
52 #include "chrome/common/chrome_paths.h"
53 #include "chrome/common/chrome_switches.h"
54 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
55 #include "chrome/common/cloud_print/cloud_print_constants.h"
56 #include "chrome/common/crash_keys.h"
57 #include "chrome/common/pref_names.h"
58 #include "components/cloud_devices/common/cloud_device_description.h"
59 #include "components/cloud_devices/common/cloud_devices_urls.h"
60 #include "components/cloud_devices/common/printer_description.h"
61 #include "components/dom_distiller/content/browser/distillable_page_utils.h"
62 #include "components/dom_distiller/core/dom_distiller_switches.h"
63 #include "components/dom_distiller/core/url_utils.h"
64 #include "components/printing/common/print_messages.h"
65 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
66 #include "components/signin/core/browser/profile_oauth2_token_service.h"
67 #include "components/signin/core/browser/signin_manager.h"
68 #include "components/signin/core/common/profile_management_switches.h"
69 #include "content/public/browser/browser_context.h"
70 #include "content/public/browser/browser_thread.h"
71 #include "content/public/browser/navigation_controller.h"
72 #include "content/public/browser/navigation_entry.h"
73 #include "content/public/browser/render_process_host.h"
74 #include "content/public/browser/render_view_host.h"
75 #include "content/public/browser/web_contents.h"
76 #include "content/public/browser/web_ui.h"
77 #include "google_apis/gaia/oauth2_token_service.h"
78 #include "net/base/url_util.h"
79 #include "printing/backend/print_backend.h"
80 #include "printing/backend/print_backend_consts.h"
81 #include "printing/metafile.h"
82 #include "printing/pdf_metafile_skia.h"
83 #include "printing/pdf_render_settings.h"
84 #include "printing/print_settings.h"
85 #include "printing/printing_context.h"
86 #include "printing/units.h"
87 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
89 #if defined(OS_CHROMEOS)
90 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
91 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
92 #endif
94 #if defined(ENABLE_SERVICE_DISCOVERY)
95 #include "chrome/browser/local_discovery/privet_constants.h"
96 #endif
98 using content::BrowserThread;
99 using content::RenderViewHost;
100 using content::WebContents;
102 namespace {
104 enum UserActionBuckets {
105 PRINT_TO_PRINTER,
106 PRINT_TO_PDF,
107 CANCEL,
108 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
109 PREVIEW_FAILED,
110 PREVIEW_STARTED,
111 INITIATOR_CRASHED, // UNUSED
112 INITIATOR_CLOSED,
113 PRINT_WITH_CLOUD_PRINT,
114 PRINT_WITH_PRIVET,
115 PRINT_WITH_EXTENSION,
116 USERACTION_BUCKET_BOUNDARY
119 enum PrintSettingsBuckets {
120 LANDSCAPE = 0,
121 PORTRAIT,
122 COLOR,
123 BLACK_AND_WHITE,
124 COLLATE,
125 SIMPLEX,
126 DUPLEX,
127 TOTAL,
128 HEADERS_AND_FOOTERS,
129 CSS_BACKGROUND,
130 SELECTION_ONLY,
131 EXTERNAL_PDF_PREVIEW,
132 PAGE_RANGE,
133 DEFAULT_MEDIA,
134 NON_DEFAULT_MEDIA,
135 COPIES,
136 NON_DEFAULT_MARGINS,
137 PRINT_SETTINGS_BUCKET_BOUNDARY
140 void ReportUserActionHistogram(enum UserActionBuckets event) {
141 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
142 USERACTION_BUCKET_BOUNDARY);
145 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
146 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
147 PRINT_SETTINGS_BUCKET_BOUNDARY);
150 // Name of a dictionary field holding cloud print related data;
151 const char kAppState[] = "appState";
152 // Name of a dictionary field holding the initiator title.
153 const char kInitiatorTitle[] = "initiatorTitle";
154 // Name of a dictionary field holding the measurement system according to the
155 // locale.
156 const char kMeasurementSystem[] = "measurementSystem";
157 // Name of a dictionary field holding the number format according to the locale.
158 const char kNumberFormat[] = "numberFormat";
159 // Name of a dictionary field specifying whether to print automatically in
160 // kiosk mode. See http://crbug.com/31395.
161 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
162 // Dictionary field to indicate whether Chrome is running in forced app (app
163 // kiosk) mode. It's not the same as desktop Chrome kiosk (the one above).
164 const char kAppKioskMode[] = "appKioskMode";
165 // Dictionary field to store Cloud Print base URL.
166 const char kCloudPrintUrl[] = "cloudPrintUrl";
167 #if defined(OS_WIN)
168 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
169 #endif
170 // Name of a dictionary field holding the state of selection for document.
171 const char kDocumentHasSelection[] = "documentHasSelection";
173 // Id of the predefined PDF printer.
174 const char kLocalPdfPrinterId[] = "Save as PDF";
176 // Additional printer capability setting keys.
177 const char kPrinterId[] = "printerId";
178 const char kPrinterCapabilities[] = "capabilities";
180 // Get the print job settings dictionary from |args|. The caller takes
181 // ownership of the returned DictionaryValue. Returns NULL on failure.
182 base::DictionaryValue* GetSettingsDictionary(const base::ListValue* args) {
183 std::string json_str;
184 if (!args->GetString(0, &json_str)) {
185 NOTREACHED() << "Could not read JSON argument";
186 return NULL;
188 if (json_str.empty()) {
189 NOTREACHED() << "Empty print job settings";
190 return NULL;
192 scoped_ptr<base::DictionaryValue> settings(
193 static_cast<base::DictionaryValue*>(
194 base::JSONReader::Read(json_str).release()));
195 if (!settings.get() || !settings->IsType(base::Value::TYPE_DICTIONARY)) {
196 NOTREACHED() << "Print job settings must be a dictionary.";
197 return NULL;
200 if (settings->empty()) {
201 NOTREACHED() << "Print job settings dictionary is empty";
202 return NULL;
205 return settings.release();
208 // Track the popularity of print settings and report the stats.
209 void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
210 ReportPrintSettingHistogram(TOTAL);
212 const base::ListValue* page_range_array = NULL;
213 if (settings.GetList(printing::kSettingPageRange, &page_range_array) &&
214 !page_range_array->empty()) {
215 ReportPrintSettingHistogram(PAGE_RANGE);
218 const base::DictionaryValue* media_size_value = NULL;
219 if (settings.GetDictionary(printing::kSettingMediaSize, &media_size_value) &&
220 !media_size_value->empty()) {
221 bool is_default = false;
222 if (media_size_value->GetBoolean(printing::kSettingMediaSizeIsDefault,
223 &is_default) &&
224 is_default) {
225 ReportPrintSettingHistogram(DEFAULT_MEDIA);
226 } else {
227 ReportPrintSettingHistogram(NON_DEFAULT_MEDIA);
231 bool landscape = false;
232 if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
233 ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
235 int copies = 1;
236 if (settings.GetInteger(printing::kSettingCopies, &copies) && copies > 1)
237 ReportPrintSettingHistogram(COPIES);
239 bool collate = false;
240 if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
241 ReportPrintSettingHistogram(COLLATE);
243 int duplex_mode = 0;
244 if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
245 ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
247 int color_mode = 0;
248 if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
249 ReportPrintSettingHistogram(
250 printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
253 int margins_type = 0;
254 if (settings.GetInteger(printing::kSettingMarginsType, &margins_type) &&
255 margins_type != 0) {
256 ReportPrintSettingHistogram(NON_DEFAULT_MARGINS);
259 bool headers = false;
260 if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
261 headers) {
262 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
265 bool css_background = false;
266 if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
267 &css_background) && css_background) {
268 ReportPrintSettingHistogram(CSS_BACKGROUND);
271 bool selection_only = false;
272 if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
273 &selection_only) && selection_only) {
274 ReportPrintSettingHistogram(SELECTION_ONLY);
277 bool external_preview = false;
278 if (settings.GetBoolean(printing::kSettingOpenPDFInPreview,
279 &external_preview) && external_preview) {
280 ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW);
284 // Callback that stores a PDF file on disk.
285 void PrintToPdfCallback(const scoped_refptr<base::RefCountedBytes>& data,
286 const base::FilePath& path,
287 const base::Closure& pdf_file_saved_closure) {
288 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
289 printing::PdfMetafileSkia metafile;
290 metafile.InitFromData(static_cast<const void*>(data->front()), data->size());
291 base::File file(path,
292 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
293 metafile.SaveTo(&file);
294 if (!pdf_file_saved_closure.is_null())
295 pdf_file_saved_closure.Run();
298 std::string GetDefaultPrinterOnFileThread() {
299 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
301 scoped_refptr<printing::PrintBackend> print_backend(
302 printing::PrintBackend::CreateInstance(NULL));
304 std::string default_printer = print_backend->GetDefaultPrinterName();
305 VLOG(1) << "Default Printer: " << default_printer;
306 return default_printer;
309 class PrintingContextDelegate : public printing::PrintingContext::Delegate {
310 public:
311 // PrintingContext::Delegate methods.
312 gfx::NativeView GetParentView() override { return NULL; }
313 std::string GetAppLocale() override {
314 return g_browser_process->GetApplicationLocale();
318 gfx::Size GetDefaultPdfMediaSizeMicrons() {
319 PrintingContextDelegate delegate;
320 scoped_ptr<printing::PrintingContext> printing_context(
321 printing::PrintingContext::Create(&delegate));
322 if (printing::PrintingContext::OK != printing_context->UsePdfSettings() ||
323 printing_context->settings().device_units_per_inch() <= 0) {
324 return gfx::Size();
326 gfx::Size pdf_media_size = printing_context->GetPdfPaperSizeDeviceUnits();
327 float deviceMicronsPerDeviceUnit =
328 (printing::kHundrethsMMPerInch * 10.0f) /
329 printing_context->settings().device_units_per_inch();
330 return gfx::Size(pdf_media_size.width() * deviceMicronsPerDeviceUnit,
331 pdf_media_size.height() * deviceMicronsPerDeviceUnit);
334 typedef base::Callback<void(const base::DictionaryValue*)>
335 GetPdfCapabilitiesCallback;
337 scoped_ptr<base::DictionaryValue> GetPdfCapabilitiesOnFileThread(
338 const std::string& locale) {
339 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
341 cloud_devices::CloudDeviceDescription description;
342 using namespace cloud_devices::printer;
344 OrientationCapability orientation;
345 orientation.AddOption(cloud_devices::printer::PORTRAIT);
346 orientation.AddOption(cloud_devices::printer::LANDSCAPE);
347 orientation.AddDefaultOption(AUTO_ORIENTATION, true);
348 orientation.SaveTo(&description);
350 ColorCapability color;
352 Color standard_color(STANDARD_COLOR);
353 standard_color.vendor_id = base::IntToString(printing::COLOR);
354 color.AddDefaultOption(standard_color, true);
356 color.SaveTo(&description);
358 static const cloud_devices::printer::MediaType kPdfMedia[] = {
359 ISO_A4,
360 ISO_A3,
361 NA_LETTER,
362 NA_LEGAL,
363 NA_LEDGER
365 const gfx::Size default_media_size = GetDefaultPdfMediaSizeMicrons();
366 Media default_media(
367 "", "", default_media_size.width(), default_media_size.height());
368 if (!default_media.MatchBySize() ||
369 std::find(kPdfMedia,
370 kPdfMedia + arraysize(kPdfMedia),
371 default_media.type) == kPdfMedia + arraysize(kPdfMedia)) {
372 default_media = Media(locale == "en-US" ? NA_LETTER : ISO_A4);
374 MediaCapability media;
375 for (size_t i = 0; i < arraysize(kPdfMedia); ++i) {
376 Media media_option(kPdfMedia[i]);
377 media.AddDefaultOption(media_option,
378 default_media.type == media_option.type);
380 media.SaveTo(&description);
382 return scoped_ptr<base::DictionaryValue>(description.root().DeepCopy());
385 scoped_ptr<base::DictionaryValue> GetLocalPrinterCapabilitiesOnFileThread(
386 const std::string& printer_name) {
387 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
389 scoped_refptr<printing::PrintBackend> print_backend(
390 printing::PrintBackend::CreateInstance(NULL));
392 VLOG(1) << "Get printer capabilities start for " << printer_name;
393 crash_keys::ScopedPrinterInfo crash_key(
394 print_backend->GetPrinterDriverInfo(printer_name));
396 if (!print_backend->IsValidPrinter(printer_name)) {
397 LOG(WARNING) << "Invalid printer " << printer_name;
398 return scoped_ptr<base::DictionaryValue>();
401 printing::PrinterSemanticCapsAndDefaults info;
402 if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
403 LOG(WARNING) << "Failed to get capabilities for " << printer_name;
404 return scoped_ptr<base::DictionaryValue>();
407 scoped_ptr<base::DictionaryValue> description(
408 cloud_print::PrinterSemanticCapsAndDefaultsToCdd(info));
409 if (!description) {
410 LOG(WARNING) << "Failed to convert capabilities for " << printer_name;
411 return scoped_ptr<base::DictionaryValue>();
414 return description.Pass();
417 void EnumeratePrintersOnFileThread(base::ListValue* printers) {
418 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
420 scoped_refptr<printing::PrintBackend> print_backend(
421 printing::PrintBackend::CreateInstance(NULL));
423 VLOG(1) << "Enumerate printers start";
424 printing::PrinterList printer_list;
425 print_backend->EnumeratePrinters(&printer_list);
427 for (printing::PrinterList::iterator it = printer_list.begin();
428 it != printer_list.end(); ++it) {
429 base::DictionaryValue* printer_info = new base::DictionaryValue;
430 printers->Append(printer_info);
431 std::string printer_name;
432 std::string printer_description;
433 #if defined(OS_MACOSX)
434 // On Mac, |it->printer_description| specifies the printer name and
435 // |it->printer_name| specifies the device name / printer queue name.
436 printer_name = it->printer_description;
437 if (!it->options[kDriverNameTagName].empty())
438 printer_description = it->options[kDriverNameTagName];
439 #else
440 printer_name = it->printer_name;
441 printer_description = it->printer_description;
442 #endif
443 printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
444 printer_info->SetString(printing::kSettingPrinterDescription,
445 printer_description);
446 printer_info->SetString(printing::kSettingPrinterName, printer_name);
447 VLOG(1) << "Found printer " << printer_name
448 << " with device name " << it->printer_name;
450 base::DictionaryValue* options = new base::DictionaryValue;
451 printer_info->Set(printing::kSettingPrinterOptions, options);
452 for (std::map<std::string, std::string>::iterator opt = it->options.begin();
453 opt != it->options.end();
454 ++opt) {
455 options->SetString(opt->first, opt->second);
458 VLOG(1) << "Found printer " << printer_name << " with device name "
459 << it->printer_name;
461 VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
462 << " printers";
465 typedef base::Callback<void(const base::DictionaryValue*)>
466 GetPrinterCapabilitiesSuccessCallback;
467 typedef base::Callback<void(const std::string&)>
468 GetPrinterCapabilitiesFailureCallback;
470 void GetPrinterCapabilitiesOnFileThread(
471 const std::string& printer_name,
472 const std::string& locale,
473 const GetPrinterCapabilitiesSuccessCallback& success_cb,
474 const GetPrinterCapabilitiesFailureCallback& failure_cb) {
475 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
476 DCHECK(!printer_name.empty());
478 scoped_ptr<base::DictionaryValue> printer_capabilities(
479 printer_name == kLocalPdfPrinterId ?
480 GetPdfCapabilitiesOnFileThread(locale) :
481 GetLocalPrinterCapabilitiesOnFileThread(printer_name));
482 if (!printer_capabilities) {
483 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
484 base::Bind(failure_cb, printer_name));
485 return;
488 scoped_ptr<base::DictionaryValue> printer_info(new base::DictionaryValue);
489 printer_info->SetString(kPrinterId, printer_name);
490 printer_info->Set(kPrinterCapabilities, printer_capabilities.release());
492 BrowserThread::PostTask(
493 BrowserThread::UI, FROM_HERE,
494 base::Bind(success_cb, base::Owned(printer_info.release())));
497 base::LazyInstance<printing::StickySettings> g_sticky_settings =
498 LAZY_INSTANCE_INITIALIZER;
500 printing::StickySettings* GetStickySettings() {
501 return g_sticky_settings.Pointer();
504 // Returns a unique path for |path|, just like with downloads.
505 base::FilePath GetUniquePath(const base::FilePath& path) {
506 base::FilePath unique_path = path;
507 int uniquifier =
508 base::GetUniquePathNumber(path, base::FilePath::StringType());
509 if (uniquifier > 0) {
510 unique_path = unique_path.InsertBeforeExtensionASCII(
511 base::StringPrintf(" (%d)", uniquifier));
513 return unique_path;
516 } // namespace
518 class PrintPreviewHandler::AccessTokenService
519 : public OAuth2TokenService::Consumer {
520 public:
521 explicit AccessTokenService(PrintPreviewHandler* handler)
522 : OAuth2TokenService::Consumer("print_preview"),
523 handler_(handler) {
526 void RequestToken(const std::string& type) {
527 if (requests_.find(type) != requests_.end())
528 return; // Already in progress.
530 OAuth2TokenService* service = NULL;
531 std::string account_id;
532 if (type == "profile") {
533 Profile* profile = Profile::FromWebUI(handler_->web_ui());
534 if (profile) {
535 ProfileOAuth2TokenService* token_service =
536 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
537 SigninManagerBase* signin_manager =
538 SigninManagerFactory::GetInstance()->GetForProfile(profile);
539 account_id = signin_manager->GetAuthenticatedAccountId();
540 service = token_service;
542 } else if (type == "device") {
543 #if defined(OS_CHROMEOS)
544 chromeos::DeviceOAuth2TokenService* token_service =
545 chromeos::DeviceOAuth2TokenServiceFactory::Get();
546 account_id = token_service->GetRobotAccountId();
547 service = token_service;
548 #endif
551 if (service) {
552 OAuth2TokenService::ScopeSet oauth_scopes;
553 oauth_scopes.insert(cloud_devices::kCloudPrintAuthScope);
554 scoped_ptr<OAuth2TokenService::Request> request(
555 service->StartRequest(account_id, oauth_scopes, this));
556 requests_[type].reset(request.release());
557 } else {
558 handler_->SendAccessToken(type, std::string()); // Unknown type.
562 void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
563 const std::string& access_token,
564 const base::Time& expiration_time) override {
565 OnServiceResponce(request, access_token);
568 void OnGetTokenFailure(const OAuth2TokenService::Request* request,
569 const GoogleServiceAuthError& error) override {
570 OnServiceResponce(request, std::string());
573 private:
574 void OnServiceResponce(const OAuth2TokenService::Request* request,
575 const std::string& access_token) {
576 for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
577 if (i->second == request) {
578 handler_->SendAccessToken(i->first, access_token);
579 requests_.erase(i);
580 return;
583 NOTREACHED();
586 typedef std::map<std::string,
587 linked_ptr<OAuth2TokenService::Request> > Requests;
588 Requests requests_;
589 PrintPreviewHandler* handler_;
591 DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
594 PrintPreviewHandler::PrintPreviewHandler()
595 : regenerate_preview_request_count_(0),
596 manage_printers_dialog_request_count_(0),
597 manage_cloud_printers_dialog_request_count_(0),
598 reported_failed_preview_(false),
599 has_logged_printers_count_(false),
600 gaia_cookie_manager_service_(NULL),
601 weak_factory_(this) {
602 ReportUserActionHistogram(PREVIEW_STARTED);
605 PrintPreviewHandler::~PrintPreviewHandler() {
606 if (select_file_dialog_.get())
607 select_file_dialog_->ListenerDestroyed();
609 UnregisterForGaiaCookieChanges();
612 void PrintPreviewHandler::RegisterMessages() {
613 web_ui()->RegisterMessageCallback("getPrinters",
614 base::Bind(&PrintPreviewHandler::HandleGetPrinters,
615 base::Unretained(this)));
616 web_ui()->RegisterMessageCallback("getPreview",
617 base::Bind(&PrintPreviewHandler::HandleGetPreview,
618 base::Unretained(this)));
619 web_ui()->RegisterMessageCallback("print",
620 base::Bind(&PrintPreviewHandler::HandlePrint,
621 base::Unretained(this)));
622 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
623 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
624 base::Unretained(this)));
625 #if defined(ENABLE_BASIC_PRINTING)
626 web_ui()->RegisterMessageCallback("showSystemDialog",
627 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
628 base::Unretained(this)));
629 #endif // ENABLE_BASIC_PRINTING
630 web_ui()->RegisterMessageCallback("signIn",
631 base::Bind(&PrintPreviewHandler::HandleSignin,
632 base::Unretained(this)));
633 web_ui()->RegisterMessageCallback("getAccessToken",
634 base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
635 base::Unretained(this)));
636 web_ui()->RegisterMessageCallback("manageCloudPrinters",
637 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
638 base::Unretained(this)));
639 web_ui()->RegisterMessageCallback("manageLocalPrinters",
640 base::Bind(&PrintPreviewHandler::HandleManagePrinters,
641 base::Unretained(this)));
642 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
643 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
644 base::Unretained(this)));
645 web_ui()->RegisterMessageCallback("hidePreview",
646 base::Bind(&PrintPreviewHandler::HandleHidePreview,
647 base::Unretained(this)));
648 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
649 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
650 base::Unretained(this)));
651 web_ui()->RegisterMessageCallback("saveAppState",
652 base::Bind(&PrintPreviewHandler::HandleSaveAppState,
653 base::Unretained(this)));
654 web_ui()->RegisterMessageCallback("getInitialSettings",
655 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
656 base::Unretained(this)));
657 web_ui()->RegisterMessageCallback("forceOpenNewTab",
658 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
659 base::Unretained(this)));
660 web_ui()->RegisterMessageCallback("getPrivetPrinters",
661 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
662 base::Unretained(this)));
663 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
664 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
665 base::Unretained(this)));
666 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
667 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
668 base::Unretained(this)));
669 web_ui()->RegisterMessageCallback(
670 "getExtensionPrinters",
671 base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinters,
672 base::Unretained(this)));
673 web_ui()->RegisterMessageCallback(
674 "getExtensionPrinterCapabilities",
675 base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinterCapabilities,
676 base::Unretained(this)));
677 web_ui()->RegisterMessageCallback(
678 "grantExtensionPrinterAccess",
679 base::Bind(&PrintPreviewHandler::HandleGrantExtensionPrinterAccess,
680 base::Unretained(this)));
681 RegisterForGaiaCookieChanges();
684 bool PrintPreviewHandler::PrivetPrintingEnabled() {
685 #if defined(ENABLE_SERVICE_DISCOVERY)
686 return true;
687 #else
688 return false;
689 #endif
692 WebContents* PrintPreviewHandler::preview_web_contents() const {
693 return web_ui()->GetWebContents();
696 PrintPreviewUI* PrintPreviewHandler::print_preview_ui() const {
697 return static_cast<PrintPreviewUI*>(web_ui()->GetController());
700 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
701 base::ListValue* results = new base::ListValue;
702 BrowserThread::PostTaskAndReply(
703 BrowserThread::FILE, FROM_HERE,
704 base::Bind(&EnumeratePrintersOnFileThread,
705 base::Unretained(results)),
706 base::Bind(&PrintPreviewHandler::SetupPrinterList,
707 weak_factory_.GetWeakPtr(),
708 base::Owned(results)));
711 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
712 if (!PrivetPrintingEnabled())
713 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
714 #if defined(ENABLE_SERVICE_DISCOVERY)
715 using local_discovery::ServiceDiscoverySharedClient;
716 scoped_refptr<ServiceDiscoverySharedClient> service_discovery =
717 ServiceDiscoverySharedClient::GetInstance();
718 StartPrivetLister(service_discovery);
719 #endif // ENABLE_SERVICE_DISCOVERY
722 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
723 const base::ListValue* args) {
724 #if defined(ENABLE_SERVICE_DISCOVERY)
725 if (PrivetPrintingEnabled() && printer_lister_) {
726 printer_lister_->Stop();
728 #endif
731 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
732 const base::ListValue* args) {
733 #if defined(ENABLE_SERVICE_DISCOVERY)
734 std::string name;
735 bool success = args->GetString(0, &name);
736 DCHECK(success);
738 CreatePrivetHTTP(
739 name,
740 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
741 base::Unretained(this)));
742 #endif
745 void PrintPreviewHandler::HandleGetExtensionPrinters(
746 const base::ListValue* args) {
747 EnsureExtensionPrinterHandlerSet();
748 // Make sure all in progress requests are canceled before new printer search
749 // starts.
750 extension_printer_handler_->Reset();
751 extension_printer_handler_->StartGetPrinters(base::Bind(
752 &PrintPreviewHandler::OnGotPrintersForExtension, base::Unretained(this)));
755 void PrintPreviewHandler::HandleGrantExtensionPrinterAccess(
756 const base::ListValue* args) {
757 std::string printer_id;
758 bool ok = args->GetString(0, &printer_id);
759 DCHECK(ok);
761 EnsureExtensionPrinterHandlerSet();
762 extension_printer_handler_->StartGrantPrinterAccess(
763 printer_id, base::Bind(&PrintPreviewHandler::OnGotExtensionPrinterInfo,
764 base::Unretained(this), printer_id));
767 void PrintPreviewHandler::HandleGetExtensionPrinterCapabilities(
768 const base::ListValue* args) {
769 std::string printer_id;
770 bool ok = args->GetString(0, &printer_id);
771 DCHECK(ok);
773 EnsureExtensionPrinterHandlerSet();
774 extension_printer_handler_->StartGetCapability(
775 printer_id,
776 base::Bind(&PrintPreviewHandler::OnGotExtensionPrinterCapabilities,
777 base::Unretained(this)));
780 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
781 DCHECK_EQ(3U, args->GetSize());
782 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
783 if (!settings.get())
784 return;
785 int request_id = -1;
786 if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
787 return;
789 print_preview_ui()->OnPrintPreviewRequest(request_id);
790 // Add an additional key in order to identify |print_preview_ui| later on
791 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
792 // thread.
793 settings->SetInteger(printing::kPreviewUIID,
794 print_preview_ui()->GetIDForPrintPreviewUI());
796 // Increment request count.
797 ++regenerate_preview_request_count_;
799 WebContents* initiator = GetInitiator();
800 if (!initiator) {
801 ReportUserActionHistogram(INITIATOR_CLOSED);
802 print_preview_ui()->OnClosePrintPreviewDialog();
803 return;
806 // Retrieve the page title and url and send it to the renderer process if
807 // headers and footers are to be displayed.
808 bool display_header_footer = false;
809 if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
810 &display_header_footer)) {
811 NOTREACHED();
813 if (display_header_footer) {
814 settings->SetString(printing::kSettingHeaderFooterTitle,
815 initiator->GetTitle());
816 std::string url;
817 content::NavigationEntry* entry =
818 initiator->GetController().GetLastCommittedEntry();
819 if (entry)
820 url = entry->GetVirtualURL().spec();
821 settings->SetString(printing::kSettingHeaderFooterURL, url);
824 bool generate_draft_data = false;
825 bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
826 &generate_draft_data);
827 DCHECK(success);
829 if (!generate_draft_data) {
830 double draft_page_count_double = -1;
831 success = args->GetDouble(1, &draft_page_count_double);
832 DCHECK(success);
833 int draft_page_count = static_cast<int>(draft_page_count_double);
835 bool preview_modifiable = false;
836 success = args->GetBoolean(2, &preview_modifiable);
837 DCHECK(success);
839 if (draft_page_count != -1 && preview_modifiable &&
840 print_preview_ui()->GetAvailableDraftPageCount() != draft_page_count) {
841 settings->SetBoolean(printing::kSettingGenerateDraftData, true);
845 VLOG(1) << "Print preview request start";
847 bool distill_page = false;
848 if (!settings->GetBoolean(printing::kSettingDistillPageEnabled,
849 &distill_page)) {
850 NOTREACHED();
853 bool selection_only = false;
854 if (!settings->GetBoolean(printing::kSettingShouldPrintSelectionOnly,
855 &selection_only)) {
856 NOTREACHED();
859 if (distill_page && !selection_only) {
860 print_preview_distiller_.reset(new PrintPreviewDistiller(
861 initiator, base::Bind(&PrintPreviewUI::OnPrintPreviewFailed,
862 print_preview_ui()->GetWeakPtr()),
863 settings.Pass()));
864 } else {
865 RenderViewHost* rvh = initiator->GetRenderViewHost();
866 rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
870 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
871 ReportStats();
873 // Record the number of times the user requests to regenerate preview data
874 // before printing.
875 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
876 regenerate_preview_request_count_);
878 scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
879 if (!settings.get())
880 return;
882 ReportPrintSettingsStats(*settings);
884 // Never try to add headers/footers here. It's already in the generated PDF.
885 settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
887 bool print_to_pdf = false;
888 bool is_cloud_printer = false;
889 bool print_with_privet = false;
890 bool print_with_extension = false;
892 bool open_pdf_in_preview = false;
893 #if defined(OS_MACOSX)
894 open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
895 #endif
897 if (!open_pdf_in_preview) {
898 settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
899 settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
900 settings->GetBoolean(printing::kSettingPrintWithExtension,
901 &print_with_extension);
902 is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
905 int page_count = 0;
906 settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
908 if (print_to_pdf) {
909 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
910 ReportUserActionHistogram(PRINT_TO_PDF);
911 PrintToPdf();
912 return;
915 #if defined(ENABLE_SERVICE_DISCOVERY)
916 if (print_with_privet && PrivetPrintingEnabled()) {
917 std::string printer_name;
918 std::string print_ticket;
919 std::string capabilities;
920 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
921 ReportUserActionHistogram(PRINT_WITH_PRIVET);
923 int width = 0;
924 int height = 0;
925 if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
926 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
927 !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
928 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
929 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
930 width <= 0 || height <= 0) {
931 NOTREACHED();
932 base::FundamentalValue http_code_value(-1);
933 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
934 return;
937 PrintToPrivetPrinter(
938 printer_name, print_ticket, capabilities, gfx::Size(width, height));
939 return;
941 #endif
943 if (print_with_extension) {
944 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithExtension",
945 page_count);
946 ReportUserActionHistogram(PRINT_WITH_EXTENSION);
948 std::string destination_id;
949 std::string print_ticket;
950 std::string capabilities;
951 int width = 0;
952 int height = 0;
953 if (!settings->GetString(printing::kSettingDeviceName, &destination_id) ||
954 !settings->GetString(printing::kSettingTicket, &print_ticket) ||
955 !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
956 !settings->GetInteger(printing::kSettingPageWidth, &width) ||
957 !settings->GetInteger(printing::kSettingPageHeight, &height) ||
958 width <= 0 || height <= 0) {
959 NOTREACHED();
960 OnExtensionPrintResult(false, "FAILED");
961 return;
964 base::string16 title;
965 scoped_refptr<base::RefCountedBytes> data;
966 if (!GetPreviewDataAndTitle(&data, &title)) {
967 LOG(ERROR) << "Nothing to print; no preview available.";
968 OnExtensionPrintResult(false, "NO_DATA");
969 return;
972 EnsureExtensionPrinterHandlerSet();
973 extension_printer_handler_->StartPrint(
974 destination_id, capabilities, title, print_ticket,
975 gfx::Size(width, height), data,
976 base::Bind(&PrintPreviewHandler::OnExtensionPrintResult,
977 base::Unretained(this)));
978 return;
981 scoped_refptr<base::RefCountedBytes> data;
982 base::string16 title;
983 if (!GetPreviewDataAndTitle(&data, &title)) {
984 // Nothing to print, no preview available.
985 return;
988 if (is_cloud_printer) {
989 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
990 page_count);
991 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
992 SendCloudPrintJob(data.get());
993 } else {
994 bool system_dialog = false;
995 settings->GetBoolean(printing::kSettingShowSystemDialog, &system_dialog);
996 if (system_dialog) {
997 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count);
998 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
999 } else {
1000 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
1001 ReportUserActionHistogram(PRINT_TO_PRINTER);
1004 // This tries to activate the initiator as well, so do not clear the
1005 // association with the initiator yet.
1006 print_preview_ui()->OnHidePreviewDialog();
1008 // Do this so the initiator can open a new print preview dialog, while the
1009 // current print preview dialog is still handling its print job.
1010 WebContents* initiator = GetInitiator();
1011 if (initiator) {
1012 // Save initiator IDs. |PrintingMessageFilter::OnUpdatePrintSettings|
1013 // would be called when initiator info is cleared.
1014 settings->SetInteger(printing::kPreviewInitiatorHostId,
1015 initiator->GetRenderProcessHost()->GetID());
1016 settings->SetInteger(printing::kPreviewInitiatorRoutingId,
1017 initiator->GetRoutingID());
1020 ClearInitiatorDetails();
1022 // The PDF being printed contains only the pages that the user selected,
1023 // so ignore the page range and print all pages.
1024 settings->Remove(printing::kSettingPageRange, NULL);
1025 // Reset selection only flag for the same reason.
1026 settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
1028 // Set ID to know whether printing is for preview.
1029 settings->SetInteger(printing::kPreviewUIID,
1030 print_preview_ui()->GetIDForPrintPreviewUI());
1031 RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
1032 rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
1033 *settings));
1035 // For all other cases above, the preview dialog will stay open until the
1036 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
1037 // called. In the case below, since the preview dialog will be hidden and
1038 // not closed, we need to make this call.
1039 if (initiator) {
1040 printing::PrintViewManager* print_view_manager =
1041 printing::PrintViewManager::FromWebContents(initiator);
1042 print_view_manager->PrintPreviewDone();
1047 void PrintPreviewHandler::PrintToPdf() {
1048 if (!print_to_pdf_path_.empty()) {
1049 // User has already selected a path, no need to show the dialog again.
1050 PostPrintToPdfTask();
1051 } else if (!select_file_dialog_.get() ||
1052 !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
1053 preview_web_contents()->GetNativeView()))) {
1054 // Pre-populating select file dialog with print job title.
1055 base::string16 print_job_title_utf16 =
1056 print_preview_ui()->initiator_title();
1058 #if defined(OS_WIN)
1059 base::FilePath::StringType print_job_title(print_job_title_utf16);
1060 #elif defined(OS_POSIX)
1061 base::FilePath::StringType print_job_title =
1062 base::UTF16ToUTF8(print_job_title_utf16);
1063 #endif
1065 base::i18n::ReplaceIllegalCharactersInPath(&print_job_title, '_');
1066 base::FilePath default_filename(print_job_title);
1067 default_filename =
1068 default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
1070 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1071 bool prompt_user = !cmdline->HasSwitch(switches::kKioskModePrinting);
1072 SelectFile(default_filename, prompt_user);
1076 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
1077 print_preview_ui()->OnHidePreviewDialog();
1080 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
1081 const base::ListValue* /*args*/) {
1082 WebContents* initiator = GetInitiator();
1083 if (initiator)
1084 ClearInitiatorDetails();
1085 chrome::ShowPrintErrorDialog();
1088 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
1089 std::string data_to_save;
1090 printing::StickySettings* sticky_settings = GetStickySettings();
1091 if (args->GetString(0, &data_to_save) && !data_to_save.empty())
1092 sticky_settings->StoreAppState(data_to_save);
1093 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1094 preview_web_contents()->GetBrowserContext())->GetPrefs());
1097 void PrintPreviewHandler::HandleGetPrinterCapabilities(
1098 const base::ListValue* args) {
1099 std::string printer_name;
1100 bool ret = args->GetString(0, &printer_name);
1101 if (!ret || printer_name.empty())
1102 return;
1104 GetPrinterCapabilitiesSuccessCallback success_cb =
1105 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
1106 weak_factory_.GetWeakPtr());
1107 GetPrinterCapabilitiesFailureCallback failure_cb =
1108 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
1109 weak_factory_.GetWeakPtr());
1110 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1111 base::Bind(&GetPrinterCapabilitiesOnFileThread,
1112 printer_name,
1113 g_browser_process->GetApplicationLocale(),
1114 success_cb, failure_cb));
1117 void PrintPreviewHandler::OnSigninComplete() {
1118 if (print_preview_ui())
1119 print_preview_ui()->OnReloadPrintersList();
1122 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
1123 bool add_account = false;
1124 bool success = args->GetBoolean(0, &add_account);
1125 DCHECK(success);
1127 Profile* profile = Profile::FromBrowserContext(
1128 preview_web_contents()->GetBrowserContext());
1129 chrome::ScopedTabbedBrowserDisplayer displayer(
1130 profile, chrome::GetActiveDesktop());
1131 print_dialog_cloud::CreateCloudPrintSigninTab(
1132 displayer.browser(),
1133 add_account,
1134 base::Bind(&PrintPreviewHandler::OnSigninComplete,
1135 weak_factory_.GetWeakPtr()));
1138 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
1139 std::string type;
1140 if (!args->GetString(0, &type))
1141 return;
1142 if (!token_service_)
1143 token_service_.reset(new AccessTokenService(this));
1144 token_service_->RequestToken(type);
1147 void PrintPreviewHandler::HandleManageCloudPrint(
1148 const base::ListValue* args) {
1149 ++manage_cloud_printers_dialog_request_count_;
1150 GURL manage_url(cloud_devices::GetCloudPrintRelativeURL("manage.html"));
1151 std::string user;
1152 if (!args->GetString(0, &user))
1153 return;
1154 if (!user.empty())
1155 manage_url = net::AppendQueryParameter(manage_url, "user", user);
1156 preview_web_contents()->OpenURL(content::OpenURLParams(
1157 manage_url,
1158 content::Referrer(),
1159 NEW_FOREGROUND_TAB,
1160 ui::PAGE_TRANSITION_LINK,
1161 false));
1164 #if defined(ENABLE_BASIC_PRINTING)
1165 void PrintPreviewHandler::HandleShowSystemDialog(
1166 const base::ListValue* /*args*/) {
1167 ReportStats();
1168 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1170 WebContents* initiator = GetInitiator();
1171 if (!initiator)
1172 return;
1174 printing::PrintViewManager* print_view_manager =
1175 printing::PrintViewManager::FromWebContents(initiator);
1176 print_view_manager->set_observer(this);
1177 print_view_manager->PrintForSystemDialogNow();
1179 // Cancel the pending preview request if exists.
1180 print_preview_ui()->OnCancelPendingPreviewRequest();
1182 #endif // ENABLE_BASIC_PRINTING
1184 void PrintPreviewHandler::HandleManagePrinters(
1185 const base::ListValue* /*args*/) {
1186 ++manage_printers_dialog_request_count_;
1187 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1190 void PrintPreviewHandler::HandleClosePreviewDialog(
1191 const base::ListValue* /*args*/) {
1192 ReportStats();
1193 ReportUserActionHistogram(CANCEL);
1195 // Record the number of times the user requests to regenerate preview data
1196 // before cancelling.
1197 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1198 regenerate_preview_request_count_);
1201 void PrintPreviewHandler::ReportStats() {
1202 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1203 manage_printers_dialog_request_count_);
1204 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1205 manage_cloud_printers_dialog_request_count_);
1208 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1209 base::DictionaryValue* settings) {
1211 // Getting the measurement system based on the locale.
1212 UErrorCode errorCode = U_ZERO_ERROR;
1213 const char* locale = g_browser_process->GetApplicationLocale().c_str();
1214 UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1215 if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1216 system = UMS_SI;
1218 // Getting the number formatting based on the locale and writing to
1219 // dictionary.
1220 settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1221 settings->SetInteger(kMeasurementSystem, system);
1224 void PrintPreviewHandler::HandleGetInitialSettings(
1225 const base::ListValue* /*args*/) {
1226 // Send before SendInitialSettings to allow cloud printer auto select.
1227 SendCloudPrintEnabled();
1228 BrowserThread::PostTaskAndReplyWithResult(
1229 BrowserThread::FILE, FROM_HERE,
1230 base::Bind(&GetDefaultPrinterOnFileThread),
1231 base::Bind(&PrintPreviewHandler::SendInitialSettings,
1232 weak_factory_.GetWeakPtr()));
1235 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1236 std::string url;
1237 if (!args->GetString(0, &url))
1238 return;
1239 Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1240 if (!browser)
1241 return;
1242 chrome::AddSelectedTabWithURL(browser,
1243 GURL(url),
1244 ui::PAGE_TRANSITION_LINK);
1247 void PrintPreviewHandler::SendInitialSettings(
1248 const std::string& default_printer) {
1249 base::DictionaryValue initial_settings;
1250 initial_settings.SetString(kInitiatorTitle,
1251 print_preview_ui()->initiator_title());
1252 initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1253 print_preview_ui()->source_is_modifiable());
1254 initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1255 initial_settings.SetBoolean(kDocumentHasSelection,
1256 print_preview_ui()->source_has_selection());
1257 initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1258 print_preview_ui()->print_selection_only());
1259 printing::StickySettings* sticky_settings = GetStickySettings();
1260 sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1261 preview_web_contents()->GetBrowserContext())->GetPrefs());
1262 if (sticky_settings->printer_app_state()) {
1263 initial_settings.SetString(kAppState,
1264 *sticky_settings->printer_app_state());
1267 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1268 initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1269 cmdline->HasSwitch(switches::kKioskModePrinting));
1270 initial_settings.SetBoolean(kAppKioskMode,
1271 chrome::IsRunningInForcedAppMode());
1272 #if defined(OS_WIN)
1273 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1274 // so will cause the browser to appear hung, so we don't show the link in
1275 // metro.
1276 bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1277 initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1278 #endif
1280 if (print_preview_ui()->source_is_modifiable())
1281 GetNumberFormatAndMeasurementSystem(&initial_settings);
1282 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1284 WebContents* initiator = GetInitiator();
1285 if (initiator && cmdline->HasSwitch(switches::kEnableDomDistiller) &&
1286 dom_distiller::url_utils::IsUrlDistillable(
1287 initiator->GetLastCommittedURL())) {
1288 dom_distiller::IsDistillablePage(
1289 initiator, false,
1290 base::Bind(&PrintPreviewHandler::HandleIsPageDistillableResult,
1291 weak_factory_.GetWeakPtr()));
1295 void PrintPreviewHandler::HandleIsPageDistillableResult(bool distillable) {
1296 VLOG(1) << "Distillable page detection finished";
1297 if (distillable)
1298 web_ui()->CallJavascriptFunction("detectDistillablePage");
1301 void PrintPreviewHandler::ClosePreviewDialog() {
1302 print_preview_ui()->OnClosePrintPreviewDialog();
1305 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1306 const std::string& access_token) {
1307 VLOG(1) << "Get getAccessToken finished";
1308 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1309 base::StringValue(type),
1310 base::StringValue(access_token));
1313 void PrintPreviewHandler::SendPrinterCapabilities(
1314 const base::DictionaryValue* settings_info) {
1315 VLOG(1) << "Get printer capabilities finished";
1316 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1317 *settings_info);
1320 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1321 const std::string& printer_name) {
1322 VLOG(1) << "Get printer capabilities failed";
1323 base::StringValue printer_name_value(printer_name);
1324 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1325 printer_name_value);
1328 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1329 if (!has_logged_printers_count_) {
1330 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1331 has_logged_printers_count_ = true;
1334 web_ui()->CallJavascriptFunction("setPrinters", *printers);
1337 void PrintPreviewHandler::SendCloudPrintEnabled() {
1338 Profile* profile = Profile::FromBrowserContext(
1339 preview_web_contents()->GetBrowserContext());
1340 PrefService* prefs = profile->GetPrefs();
1341 if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1342 base::DictionaryValue settings;
1343 settings.SetString(kCloudPrintUrl,
1344 GURL(cloud_devices::GetCloudPrintURL()).spec());
1345 settings.SetBoolean(kAppKioskMode, chrome::IsRunningInForcedAppMode());
1346 web_ui()->CallJavascriptFunction("setUseCloudPrint", settings);
1350 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1351 // BASE64 encode the job data.
1352 std::string raw_data(reinterpret_cast<const char*>(data->front()),
1353 data->size());
1354 std::string base64_data;
1355 base::Base64Encode(raw_data, &base64_data);
1356 base::StringValue data_value(base64_data);
1358 web_ui()->CallJavascriptFunction("printToCloud", data_value);
1361 WebContents* PrintPreviewHandler::GetInitiator() const {
1362 printing::PrintPreviewDialogController* dialog_controller =
1363 printing::PrintPreviewDialogController::GetInstance();
1364 if (!dialog_controller)
1365 return NULL;
1366 return dialog_controller->GetInitiator(preview_web_contents());
1369 void PrintPreviewHandler::OnPrintDialogShown() {
1370 ClosePreviewDialog();
1373 void PrintPreviewHandler::OnAddAccountToCookieCompleted(
1374 const std::string& account_id,
1375 const GoogleServiceAuthError& error) {
1376 OnSigninComplete();
1379 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename,
1380 bool prompt_user) {
1381 if (prompt_user) {
1382 ChromeSelectFilePolicy policy(GetInitiator());
1383 if (!policy.CanOpenSelectFileDialog()) {
1384 policy.SelectFileDenied();
1385 return ClosePreviewDialog();
1389 // Initializing |save_path_| if it is not already initialized.
1390 printing::StickySettings* sticky_settings = GetStickySettings();
1391 if (!sticky_settings->save_path()) {
1392 // Allowing IO operation temporarily. It is ok to do so here because
1393 // the select file dialog performs IO anyway in order to display the
1394 // folders and also it is modal.
1395 base::ThreadRestrictions::ScopedAllowIO allow_io;
1396 base::FilePath file_path;
1397 PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1398 sticky_settings->StoreSavePath(file_path);
1399 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1400 preview_web_contents()->GetBrowserContext())->GetPrefs());
1403 // Handle the no prompting case. Like the dialog prompt, this function
1404 // returns and eventually FileSelected() gets called.
1405 if (!prompt_user) {
1406 base::PostTaskAndReplyWithResult(
1407 BrowserThread::GetBlockingPool(),
1408 FROM_HERE,
1409 base::Bind(&GetUniquePath,
1410 sticky_settings->save_path()->Append(default_filename)),
1411 base::Bind(&PrintPreviewHandler::OnGotUniqueFileName,
1412 weak_factory_.GetWeakPtr()));
1413 return;
1416 // Otherwise prompt the user.
1417 ui::SelectFileDialog::FileTypeInfo file_type_info;
1418 file_type_info.extensions.resize(1);
1419 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1421 select_file_dialog_ =
1422 ui::SelectFileDialog::Create(this, nullptr /*policy already checked*/);
1423 select_file_dialog_->SelectFile(
1424 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1425 base::string16(),
1426 sticky_settings->save_path()->Append(default_filename),
1427 &file_type_info,
1429 base::FilePath::StringType(),
1430 platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1431 NULL);
1434 void PrintPreviewHandler::OnGotUniqueFileName(const base::FilePath& path) {
1435 FileSelected(path, 0, nullptr);
1438 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1439 WebContents* initiator = GetInitiator();
1440 if (!initiator)
1441 return;
1443 printing::PrintViewManager* print_view_manager =
1444 printing::PrintViewManager::FromWebContents(initiator);
1445 print_view_manager->set_observer(NULL);
1448 void PrintPreviewHandler::OnPrintPreviewFailed() {
1449 if (reported_failed_preview_)
1450 return;
1451 reported_failed_preview_ = true;
1452 ReportUserActionHistogram(PREVIEW_FAILED);
1455 #if defined(ENABLE_BASIC_PRINTING)
1456 void PrintPreviewHandler::ShowSystemDialog() {
1457 HandleShowSystemDialog(NULL);
1459 #endif // ENABLE_BASIC_PRINTING
1461 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1462 int /* index */,
1463 void* /* params */) {
1464 // Updating |save_path_| to the newly selected folder.
1465 printing::StickySettings* sticky_settings = GetStickySettings();
1466 sticky_settings->StoreSavePath(path.DirName());
1467 sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1468 preview_web_contents()->GetBrowserContext())->GetPrefs());
1469 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1470 print_to_pdf_path_ = path;
1471 PostPrintToPdfTask();
1474 void PrintPreviewHandler::PostPrintToPdfTask() {
1475 scoped_refptr<base::RefCountedBytes> data;
1476 base::string16 title;
1477 if (!GetPreviewDataAndTitle(&data, &title)) {
1478 NOTREACHED() << "Preview data was checked before file dialog.";
1479 return;
1481 BrowserThread::PostTask(BrowserThread::FILE,
1482 FROM_HERE,
1483 base::Bind(&PrintToPdfCallback,
1484 data,
1485 print_to_pdf_path_,
1486 pdf_file_saved_closure_));
1487 print_to_pdf_path_ = base::FilePath();
1488 ClosePreviewDialog();
1491 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1492 print_preview_ui()->OnFileSelectionCancelled();
1495 void PrintPreviewHandler::ClearInitiatorDetails() {
1496 WebContents* initiator = GetInitiator();
1497 if (!initiator)
1498 return;
1500 // We no longer require the initiator details. Remove those details associated
1501 // with the preview dialog to allow the initiator to create another preview
1502 // dialog.
1503 printing::PrintPreviewDialogController* dialog_controller =
1504 printing::PrintPreviewDialogController::GetInstance();
1505 if (dialog_controller)
1506 dialog_controller->EraseInitiatorInfo(preview_web_contents());
1509 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1510 scoped_refptr<base::RefCountedBytes>* data,
1511 base::string16* title) const {
1512 scoped_refptr<base::RefCountedBytes> tmp_data;
1513 print_preview_ui()->GetPrintPreviewDataForIndex(
1514 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1516 if (!tmp_data.get()) {
1517 // Nothing to print, no preview available.
1518 return false;
1520 DCHECK(tmp_data->size() && tmp_data->front());
1522 *data = tmp_data;
1523 *title = print_preview_ui()->initiator_title();
1524 return true;
1527 #if defined(ENABLE_SERVICE_DISCOVERY)
1529 void PrintPreviewHandler::StartPrivetLister(const scoped_refptr<
1530 local_discovery::ServiceDiscoverySharedClient>& client) {
1531 if (!PrivetPrintingEnabled())
1532 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1534 Profile* profile = Profile::FromWebUI(web_ui());
1535 DCHECK(!service_discovery_client_.get() ||
1536 service_discovery_client_.get() == client.get());
1537 service_discovery_client_ = client;
1538 printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
1539 service_discovery_client_.get(), profile->GetRequestContext(), this));
1540 printer_lister_->Start();
1543 void PrintPreviewHandler::LocalPrinterChanged(
1544 bool added,
1545 const std::string& name,
1546 bool has_local_printing,
1547 const local_discovery::DeviceDescription& description) {
1548 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1549 if (has_local_printing ||
1550 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) {
1551 base::DictionaryValue info;
1552 FillPrinterDescription(name, description, has_local_printing, &info);
1553 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1557 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1560 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1563 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1564 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1565 if (!PrivetUpdateClient(http_client.Pass()))
1566 return;
1568 privet_capabilities_operation_ =
1569 privet_http_client_->CreateCapabilitiesOperation(
1570 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1571 base::Unretained(this)));
1572 privet_capabilities_operation_->Start();
1575 bool PrintPreviewHandler::PrivetUpdateClient(
1576 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1577 if (!http_client) {
1578 SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1579 privet_http_resolution_.reset();
1580 return false;
1583 privet_local_print_operation_.reset();
1584 privet_capabilities_operation_.reset();
1585 privet_http_client_ =
1586 local_discovery::PrivetV1HTTPClient::CreateDefault(http_client.Pass());
1588 privet_http_resolution_.reset();
1590 return true;
1593 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1594 std::string print_ticket,
1595 std::string capabilities,
1596 gfx::Size page_size,
1597 scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1598 if (!PrivetUpdateClient(http_client.Pass()))
1599 return;
1601 StartPrivetLocalPrint(print_ticket, capabilities, page_size);
1604 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string& print_ticket,
1605 const std::string& capabilities,
1606 const gfx::Size& page_size) {
1607 privet_local_print_operation_ =
1608 privet_http_client_->CreateLocalPrintOperation(this);
1610 privet_local_print_operation_->SetTicket(print_ticket);
1611 privet_local_print_operation_->SetCapabilities(capabilities);
1613 scoped_refptr<base::RefCountedBytes> data;
1614 base::string16 title;
1616 if (!GetPreviewDataAndTitle(&data, &title)) {
1617 base::FundamentalValue http_code_value(-1);
1618 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1619 return;
1622 privet_local_print_operation_->SetJobname(base::UTF16ToUTF8(title));
1623 privet_local_print_operation_->SetPageSize(page_size);
1624 privet_local_print_operation_->SetData(data.get());
1626 Profile* profile = Profile::FromWebUI(web_ui());
1627 SigninManagerBase* signin_manager =
1628 SigninManagerFactory::GetForProfileIfExists(profile);
1630 if (signin_manager) {
1631 privet_local_print_operation_->SetUsername(
1632 signin_manager->GetAuthenticatedAccountInfo().email);
1635 privet_local_print_operation_->Start();
1639 void PrintPreviewHandler::OnPrivetCapabilities(
1640 const base::DictionaryValue* capabilities) {
1641 std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1643 if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError) ||
1644 !printer_lister_) {
1645 SendPrivetCapabilitiesError(name);
1646 return;
1649 base::DictionaryValue printer_info;
1650 const local_discovery::DeviceDescription* description =
1651 printer_lister_->GetDeviceDescription(name);
1653 if (!description) {
1654 SendPrivetCapabilitiesError(name);
1655 return;
1658 FillPrinterDescription(name, *description, true, &printer_info);
1660 web_ui()->CallJavascriptFunction(
1661 "onPrivetCapabilitiesSet",
1662 printer_info,
1663 *capabilities);
1665 privet_capabilities_operation_.reset();
1668 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1669 const std::string& device_name) {
1670 base::StringValue name_value(device_name);
1671 web_ui()->CallJavascriptFunction(
1672 "failedToGetPrivetPrinterCapabilities",
1673 name_value);
1676 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string& device_name,
1677 const std::string& ticket,
1678 const std::string& capabilities,
1679 const gfx::Size& page_size) {
1680 CreatePrivetHTTP(
1681 device_name,
1682 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1683 base::Unretained(this),
1684 ticket,
1685 capabilities,
1686 page_size));
1689 bool PrintPreviewHandler::CreatePrivetHTTP(
1690 const std::string& name,
1691 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1692 callback) {
1693 const local_discovery::DeviceDescription* device_description =
1694 printer_lister_ ? printer_lister_->GetDeviceDescription(name) : NULL;
1696 if (!device_description) {
1697 SendPrivetCapabilitiesError(name);
1698 return false;
1701 privet_http_factory_ =
1702 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1703 Profile::FromWebUI(web_ui())->GetRequestContext());
1704 privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(name);
1705 privet_http_resolution_->Start(device_description->address, callback);
1707 return true;
1710 void PrintPreviewHandler::OnPrivetPrintingDone(
1711 const local_discovery::PrivetLocalPrintOperation* print_operation) {
1712 ClosePreviewDialog();
1715 void PrintPreviewHandler::OnPrivetPrintingError(
1716 const local_discovery::PrivetLocalPrintOperation* print_operation,
1717 int http_code) {
1718 base::FundamentalValue http_code_value(http_code);
1719 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1722 void PrintPreviewHandler::FillPrinterDescription(
1723 const std::string& name,
1724 const local_discovery::DeviceDescription& description,
1725 bool has_local_printing,
1726 base::DictionaryValue* printer_value) {
1727 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1729 printer_value->SetString("serviceName", name);
1730 printer_value->SetString("name", description.name);
1731 printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1732 printer_value->SetBoolean(
1733 "isUnregistered",
1734 description.id.empty() &&
1735 command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos));
1736 printer_value->SetString("cloudID", description.id);
1739 #endif // defined(ENABLE_SERVICE_DISCOVERY)
1741 void PrintPreviewHandler::EnsureExtensionPrinterHandlerSet() {
1742 if (extension_printer_handler_)
1743 return;
1745 extension_printer_handler_ =
1746 PrinterHandler::CreateForExtensionPrinters(Profile::FromWebUI(web_ui()));
1749 void PrintPreviewHandler::OnGotPrintersForExtension(
1750 const base::ListValue& printers,
1751 bool done) {
1752 web_ui()->CallJavascriptFunction("onExtensionPrintersAdded", printers,
1753 base::FundamentalValue(done));
1756 void PrintPreviewHandler::OnGotExtensionPrinterInfo(
1757 const std::string& printer_id,
1758 const base::DictionaryValue& printer_info) {
1759 if (printer_info.empty()) {
1760 web_ui()->CallJavascriptFunction("failedToResolveProvisionalPrinter",
1761 base::StringValue(printer_id));
1762 return;
1765 web_ui()->CallJavascriptFunction("onProvisionalPrinterResolved",
1766 base::StringValue(printer_id),
1767 printer_info);
1770 void PrintPreviewHandler::OnGotExtensionPrinterCapabilities(
1771 const std::string& printer_id,
1772 const base::DictionaryValue& capabilities) {
1773 if (capabilities.empty()) {
1774 web_ui()->CallJavascriptFunction("failedToGetExtensionPrinterCapabilities",
1775 base::StringValue(printer_id));
1776 return;
1779 web_ui()->CallJavascriptFunction("onExtensionCapabilitiesSet",
1780 base::StringValue(printer_id), capabilities);
1783 void PrintPreviewHandler::OnExtensionPrintResult(bool success,
1784 const std::string& status) {
1785 if (success) {
1786 ClosePreviewDialog();
1787 return;
1790 // TODO(tbarzic): This function works for extension printers case too, but it
1791 // should be renamed to something more generic.
1792 web_ui()->CallJavascriptFunction("onPrivetPrintFailed",
1793 base::StringValue(status));
1796 void PrintPreviewHandler::RegisterForGaiaCookieChanges() {
1797 DCHECK(!gaia_cookie_manager_service_);
1798 Profile* profile = Profile::FromWebUI(web_ui());
1799 if (switches::IsEnableAccountConsistency() && !profile->IsOffTheRecord()) {
1800 gaia_cookie_manager_service_ =
1801 GaiaCookieManagerServiceFactory::GetForProfile(profile);
1802 if (gaia_cookie_manager_service_)
1803 gaia_cookie_manager_service_->AddObserver(this);
1807 void PrintPreviewHandler::UnregisterForGaiaCookieChanges() {
1808 if (gaia_cookie_manager_service_)
1809 gaia_cookie_manager_service_->RemoveObserver(this);
1812 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1813 const base::Closure& closure) {
1814 pdf_file_saved_closure_ = closure;