1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/command_line.h"
16 #include "base/i18n/file_util_icu.h"
17 #include "base/i18n/number_formatting.h"
18 #include "base/json/json_reader.h"
19 #include "base/lazy_instance.h"
20 #include "base/memory/linked_ptr.h"
21 #include "base/memory/ref_counted_memory.h"
22 #include "base/metrics/histogram.h"
23 #include "base/path_service.h"
24 #include "base/prefs/pref_service.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/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"
94 #if defined(ENABLE_SERVICE_DISCOVERY)
95 #include "chrome/browser/local_discovery/privet_constants.h"
98 using content::BrowserThread
;
99 using content::RenderViewHost
;
100 using content::WebContents
;
104 enum UserActionBuckets
{
108 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
,
111 INITIATOR_CRASHED
, // UNUSED
113 PRINT_WITH_CLOUD_PRINT
,
115 PRINT_WITH_EXTENSION
,
116 USERACTION_BUCKET_BOUNDARY
119 enum PrintSettingsBuckets
{
131 EXTERNAL_PDF_PREVIEW
,
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
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";
168 const char kHidePrintWithSystemDialogLink
[] = "hidePrintWithSystemDialogLink";
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";
188 if (json_str
.empty()) {
189 NOTREACHED() << "Empty print job settings";
192 scoped_ptr
<base::DictionaryValue
> settings(
193 static_cast<base::DictionaryValue
*>(
194 base::JSONReader::DeprecatedRead(json_str
)));
195 if (!settings
.get() || !settings
->IsType(base::Value::TYPE_DICTIONARY
)) {
196 NOTREACHED() << "Print job settings must be a dictionary.";
200 if (settings
->empty()) {
201 NOTREACHED() << "Print job settings dictionary is empty";
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
,
225 ReportPrintSettingHistogram(DEFAULT_MEDIA
);
227 ReportPrintSettingHistogram(NON_DEFAULT_MEDIA
);
231 bool landscape
= false;
232 if (settings
.GetBoolean(printing::kSettingLandscape
, &landscape
))
233 ReportPrintSettingHistogram(landscape
? LANDSCAPE
: PORTRAIT
);
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
);
244 if (settings
.GetInteger(printing::kSettingDuplexMode
, &duplex_mode
))
245 ReportPrintSettingHistogram(duplex_mode
? DUPLEX
: SIMPLEX
);
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
) &&
256 ReportPrintSettingHistogram(NON_DEFAULT_MARGINS
);
259 bool headers
= false;
260 if (settings
.GetBoolean(printing::kSettingHeaderFooterEnabled
, &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
{
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) {
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
[] = {
365 const gfx::Size default_media_size
= GetDefaultPdfMediaSizeMicrons();
367 "", "", default_media_size
.width(), default_media_size
.height());
368 if (!default_media
.MatchBySize() ||
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
));
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
];
440 printer_name
= it
->printer_name
;
441 printer_description
= it
->printer_description
;
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();
455 options
->SetString(opt
->first
, opt
->second
);
458 VLOG(1) << "Found printer " << printer_name
<< " with device name "
461 VLOG(1) << "Enumerate printers finished, found " << printers
->GetSize()
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
));
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
;
508 base::GetUniquePathNumber(path
, base::FilePath::StringType());
509 if (uniquifier
> 0) {
510 unique_path
= unique_path
.InsertBeforeExtensionASCII(
511 base::StringPrintf(" (%d)", uniquifier
));
518 class PrintPreviewHandler::AccessTokenService
519 : public OAuth2TokenService::Consumer
{
521 explicit AccessTokenService(PrintPreviewHandler
* handler
)
522 : OAuth2TokenService::Consumer("print_preview"),
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());
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
;
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());
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());
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
);
586 typedef std::map
<std::string
,
587 linked_ptr
<OAuth2TokenService::Request
> > 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)
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();
731 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
732 const base::ListValue
* args
) {
733 #if defined(ENABLE_SERVICE_DISCOVERY)
735 bool success
= args
->GetString(0, &name
);
740 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient
,
741 base::Unretained(this)));
745 void PrintPreviewHandler::HandleGetExtensionPrinters(
746 const base::ListValue
* args
) {
747 EnsureExtensionPrinterHandlerSet();
748 // Make sure all in progress requests are canceled before new printer search
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
);
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
);
773 EnsureExtensionPrinterHandlerSet();
774 extension_printer_handler_
->StartGetCapability(
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
));
786 if (!settings
->GetInteger(printing::kPreviewRequestID
, &request_id
))
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
793 settings
->SetInteger(printing::kPreviewUIID
,
794 print_preview_ui()->GetIDForPrintPreviewUI());
796 // Increment request count.
797 ++regenerate_preview_request_count_
;
799 WebContents
* initiator
= GetInitiator();
801 ReportUserActionHistogram(INITIATOR_CLOSED
);
802 print_preview_ui()->OnClosePrintPreviewDialog();
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
)) {
813 if (display_header_footer
) {
814 settings
->SetString(printing::kSettingHeaderFooterTitle
,
815 initiator
->GetTitle());
817 content::NavigationEntry
* entry
=
818 initiator
->GetController().GetLastCommittedEntry();
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
);
829 if (!generate_draft_data
) {
830 double draft_page_count_double
= -1;
831 success
= args
->GetDouble(1, &draft_page_count_double
);
833 int draft_page_count
= static_cast<int>(draft_page_count_double
);
835 bool preview_modifiable
= false;
836 success
= args
->GetBoolean(2, &preview_modifiable
);
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
,
853 bool selection_only
= false;
854 if (!settings
->GetBoolean(printing::kSettingShouldPrintSelectionOnly
,
859 if (distill_page
&& !selection_only
) {
860 print_preview_distiller_
.reset(new PrintPreviewDistiller(
861 initiator
, base::Bind(&PrintPreviewUI::OnPrintPreviewFailed
,
862 print_preview_ui()->GetWeakPtr()),
865 RenderViewHost
* rvh
= initiator
->GetRenderViewHost();
866 rvh
->Send(new PrintMsg_PrintPreview(rvh
->GetRoutingID(), *settings
));
870 void PrintPreviewHandler::HandlePrint(const base::ListValue
* args
) {
873 // Record the number of times the user requests to regenerate preview data
875 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
876 regenerate_preview_request_count_
);
878 scoped_ptr
<base::DictionaryValue
> settings(GetSettingsDictionary(args
));
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
);
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
);
906 settings
->GetInteger(printing::kSettingPreviewPageCount
, &page_count
);
909 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count
);
910 ReportUserActionHistogram(PRINT_TO_PDF
);
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
);
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) {
932 base::FundamentalValue
http_code_value(-1);
933 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
937 PrintToPrivetPrinter(
938 printer_name
, print_ticket
, capabilities
, gfx::Size(width
, height
));
943 if (print_with_extension
) {
944 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithExtension",
946 ReportUserActionHistogram(PRINT_WITH_EXTENSION
);
948 std::string destination_id
;
949 std::string print_ticket
;
950 std::string capabilities
;
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) {
960 OnExtensionPrintResult(false, "FAILED");
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");
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)));
981 scoped_refptr
<base::RefCountedBytes
> data
;
982 base::string16 title
;
983 if (!GetPreviewDataAndTitle(&data
, &title
)) {
984 // Nothing to print, no preview available.
988 if (is_cloud_printer
) {
989 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
991 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT
);
992 SendCloudPrintJob(data
.get());
994 bool system_dialog
= false;
995 settings
->GetBoolean(printing::kSettingShowSystemDialog
, &system_dialog
);
997 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count
);
998 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
);
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();
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(),
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.
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();
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
);
1065 base::i18n::ReplaceIllegalCharactersInPath(&print_job_title
, '_');
1066 base::FilePath
default_filename(print_job_title
);
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();
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())
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
,
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
);
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(),
1134 base::Bind(&PrintPreviewHandler::OnSigninComplete
,
1135 weak_factory_
.GetWeakPtr()));
1138 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue
* args
) {
1140 if (!args
->GetString(0, &type
))
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"));
1152 if (!args
->GetString(0, &user
))
1155 manage_url
= net::AppendQueryParameter(manage_url
, "user", user
);
1156 preview_web_contents()->OpenURL(content::OpenURLParams(
1158 content::Referrer(),
1160 ui::PAGE_TRANSITION_LINK
,
1164 #if defined(ENABLE_BASIC_PRINTING)
1165 void PrintPreviewHandler::HandleShowSystemDialog(
1166 const base::ListValue
* /*args*/) {
1168 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
);
1170 WebContents
* initiator
= GetInitiator();
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*/) {
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
)
1218 // Getting the number formatting based on the locale and writing to
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
) {
1237 if (!args
->GetString(0, &url
))
1239 Browser
* browser
= chrome::FindBrowserWithWebContents(GetInitiator());
1242 chrome::AddSelectedTabWithURL(browser
,
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());
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
1276 bool is_ash
= (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH
);
1277 initial_settings
.SetBoolean(kHidePrintWithSystemDialogLink
, is_ash
);
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(
1290 base::Bind(&PrintPreviewHandler::HandleIsPageDistillableResult
,
1291 weak_factory_
.GetWeakPtr()));
1295 void PrintPreviewHandler::HandleIsPageDistillableResult(bool distillable
) {
1296 VLOG(1) << "Distillable page detection finished";
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",
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()),
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
)
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
) {
1379 void PrintPreviewHandler::SelectFile(const base::FilePath
& default_filename
,
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.
1406 base::PostTaskAndReplyWithResult(
1407 BrowserThread::GetBlockingPool(),
1409 base::Bind(&GetUniquePath
,
1410 sticky_settings
->save_path()->Append(default_filename
)),
1411 base::Bind(&PrintPreviewHandler::OnGotUniqueFileName
,
1412 weak_factory_
.GetWeakPtr()));
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
,
1426 sticky_settings
->save_path()->Append(default_filename
),
1429 base::FilePath::StringType(),
1430 platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1434 void PrintPreviewHandler::OnGotUniqueFileName(const base::FilePath
& path
) {
1435 FileSelected(path
, 0, nullptr);
1438 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1439 WebContents
* initiator
= GetInitiator();
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_
)
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
,
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.";
1481 BrowserThread::PostTask(BrowserThread::FILE,
1483 base::Bind(&PrintToPdfCallback
,
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();
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
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.
1520 DCHECK(tmp_data
->size() && tmp_data
->front());
1523 *title
= print_preview_ui()->initiator_title();
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(
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()))
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
) {
1578 SendPrivetCapabilitiesError(privet_http_resolution_
->GetName());
1579 privet_http_resolution_
.reset();
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();
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()))
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
);
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
) ||
1645 SendPrivetCapabilitiesError(name
);
1649 base::DictionaryValue printer_info
;
1650 const local_discovery::DeviceDescription
* description
=
1651 printer_lister_
->GetDeviceDescription(name
);
1654 SendPrivetCapabilitiesError(name
);
1658 FillPrinterDescription(name
, *description
, true, &printer_info
);
1660 web_ui()->CallJavascriptFunction(
1661 "onPrivetCapabilitiesSet",
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",
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
) {
1682 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient
,
1683 base::Unretained(this),
1689 bool PrintPreviewHandler::CreatePrivetHTTP(
1690 const std::string
& name
,
1691 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback
&
1693 const local_discovery::DeviceDescription
* device_description
=
1694 printer_lister_
? printer_lister_
->GetDeviceDescription(name
) : NULL
;
1696 if (!device_description
) {
1697 SendPrivetCapabilitiesError(name
);
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
);
1710 void PrintPreviewHandler::OnPrivetPrintingDone(
1711 const local_discovery::PrivetLocalPrintOperation
* print_operation
) {
1712 ClosePreviewDialog();
1715 void PrintPreviewHandler::OnPrivetPrintingError(
1716 const local_discovery::PrivetLocalPrintOperation
* print_operation
,
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(
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_
)
1745 extension_printer_handler_
=
1746 PrinterHandler::CreateForExtensionPrinters(Profile::FromWebUI(web_ui()));
1749 void PrintPreviewHandler::OnGotPrintersForExtension(
1750 const base::ListValue
& printers
,
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
));
1765 web_ui()->CallJavascriptFunction("onProvisionalPrinterResolved",
1766 base::StringValue(printer_id
),
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
));
1779 web_ui()->CallJavascriptFunction("onExtensionCapabilitiesSet",
1780 base::StringValue(printer_id
), capabilities
);
1783 void PrintPreviewHandler::OnExtensionPrintResult(bool success
,
1784 const std::string
& status
) {
1786 ClosePreviewDialog();
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
;