1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
12 #include "base/base64.h"
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/command_line.h"
16 #include "base/i18n/file_util_icu.h"
17 #include "base/i18n/number_formatting.h"
18 #include "base/json/json_reader.h"
19 #include "base/lazy_instance.h"
20 #include "base/memory/linked_ptr.h"
21 #include "base/memory/ref_counted_memory.h"
22 #include "base/metrics/histogram.h"
23 #include "base/path_service.h"
24 #include "base/prefs/pref_service.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "base/threading/thread.h"
28 #include "base/threading/thread_restrictions.h"
29 #include "base/values.h"
30 #include "chrome/browser/app_mode/app_mode_utils.h"
31 #include "chrome/browser/browser_process.h"
32 #include "chrome/browser/platform_util.h"
33 #include "chrome/browser/printing/print_dialog_cloud.h"
34 #include "chrome/browser/printing/print_error_dialog.h"
35 #include "chrome/browser/printing/print_job_manager.h"
36 #include "chrome/browser/printing/print_preview_dialog_controller.h"
37 #include "chrome/browser/printing/print_view_manager.h"
38 #include "chrome/browser/printing/printer_manager_dialog.h"
39 #include "chrome/browser/profiles/profile.h"
40 #include "chrome/browser/signin/account_reconcilor_factory.h"
41 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
42 #include "chrome/browser/signin/signin_manager_factory.h"
43 #include "chrome/browser/ui/browser_finder.h"
44 #include "chrome/browser/ui/browser_tabstrip.h"
45 #include "chrome/browser/ui/chrome_select_file_policy.h"
46 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
47 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
48 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
49 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
50 #include "chrome/common/chrome_paths.h"
51 #include "chrome/common/chrome_switches.h"
52 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
53 #include "chrome/common/cloud_print/cloud_print_constants.h"
54 #include "chrome/common/crash_keys.h"
55 #include "chrome/common/pref_names.h"
56 #include "components/cloud_devices/common/cloud_device_description.h"
57 #include "components/cloud_devices/common/cloud_devices_urls.h"
58 #include "components/cloud_devices/common/printer_description.h"
59 #include "components/printing/common/print_messages.h"
60 #include "components/signin/core/browser/account_reconcilor.h"
61 #include "components/signin/core/browser/profile_oauth2_token_service.h"
62 #include "components/signin/core/browser/signin_manager.h"
63 #include "components/signin/core/common/profile_management_switches.h"
64 #include "content/public/browser/browser_context.h"
65 #include "content/public/browser/browser_thread.h"
66 #include "content/public/browser/navigation_controller.h"
67 #include "content/public/browser/navigation_entry.h"
68 #include "content/public/browser/render_process_host.h"
69 #include "content/public/browser/render_view_host.h"
70 #include "content/public/browser/web_contents.h"
71 #include "content/public/browser/web_ui.h"
72 #include "google_apis/gaia/oauth2_token_service.h"
73 #include "net/base/url_util.h"
74 #include "printing/backend/print_backend.h"
75 #include "printing/backend/print_backend_consts.h"
76 #include "printing/metafile.h"
77 #include "printing/pdf_metafile_skia.h"
78 #include "printing/pdf_render_settings.h"
79 #include "printing/print_settings.h"
80 #include "printing/printing_context.h"
81 #include "printing/units.h"
82 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
84 #if defined(OS_CHROMEOS)
85 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
86 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
89 #if defined(ENABLE_SERVICE_DISCOVERY)
90 #include "chrome/browser/local_discovery/privet_constants.h"
93 using content::BrowserThread
;
94 using content::RenderViewHost
;
95 using content::WebContents
;
99 enum UserActionBuckets
{
103 FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
,
106 INITIATOR_CRASHED
, // UNUSED
108 PRINT_WITH_CLOUD_PRINT
,
110 USERACTION_BUCKET_BOUNDARY
113 enum PrintSettingsBuckets
{
125 EXTERNAL_PDF_PREVIEW
,
131 PRINT_SETTINGS_BUCKET_BOUNDARY
134 void ReportUserActionHistogram(enum UserActionBuckets event
) {
135 UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event
,
136 USERACTION_BUCKET_BOUNDARY
);
139 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting
) {
140 UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting
,
141 PRINT_SETTINGS_BUCKET_BOUNDARY
);
144 // Name of a dictionary field holding cloud print related data;
145 const char kAppState
[] = "appState";
146 // Name of a dictionary field holding the initiator title.
147 const char kInitiatorTitle
[] = "initiatorTitle";
148 // Name of a dictionary field holding the measurement system according to the
150 const char kMeasurementSystem
[] = "measurementSystem";
151 // Name of a dictionary field holding the number format according to the locale.
152 const char kNumberFormat
[] = "numberFormat";
153 // Name of a dictionary field specifying whether to print automatically in
154 // kiosk mode. See http://crbug.com/31395.
155 const char kPrintAutomaticallyInKioskMode
[] = "printAutomaticallyInKioskMode";
156 // Dictionary field to indicate whether Chrome is running in forced app (app
157 // kiosk) mode. It's not the same as desktop Chrome kiosk (the one above).
158 const char kAppKioskMode
[] = "appKioskMode";
159 // Dictionary field to store Cloud Print base URL.
160 const char kCloudPrintUrl
[] = "cloudPrintUrl";
162 const char kHidePrintWithSystemDialogLink
[] = "hidePrintWithSystemDialogLink";
164 // Name of a dictionary field holding the state of selection for document.
165 const char kDocumentHasSelection
[] = "documentHasSelection";
167 // Id of the predefined PDF printer.
168 const char kLocalPdfPrinterId
[] = "Save as PDF";
170 // Additional printer capability setting keys.
171 const char kPrinterId
[] = "printerId";
172 const char kPrinterCapabilities
[] = "capabilities";
174 // Get the print job settings dictionary from |args|. The caller takes
175 // ownership of the returned DictionaryValue. Returns NULL on failure.
176 base::DictionaryValue
* GetSettingsDictionary(const base::ListValue
* args
) {
177 std::string json_str
;
178 if (!args
->GetString(0, &json_str
)) {
179 NOTREACHED() << "Could not read JSON argument";
182 if (json_str
.empty()) {
183 NOTREACHED() << "Empty print job settings";
186 scoped_ptr
<base::DictionaryValue
> settings(
187 static_cast<base::DictionaryValue
*>(
188 base::JSONReader::Read(json_str
)));
189 if (!settings
.get() || !settings
->IsType(base::Value::TYPE_DICTIONARY
)) {
190 NOTREACHED() << "Print job settings must be a dictionary.";
194 if (settings
->empty()) {
195 NOTREACHED() << "Print job settings dictionary is empty";
199 return settings
.release();
202 // Track the popularity of print settings and report the stats.
203 void ReportPrintSettingsStats(const base::DictionaryValue
& settings
) {
204 ReportPrintSettingHistogram(TOTAL
);
206 const base::ListValue
* page_range_array
= NULL
;
207 if (settings
.GetList(printing::kSettingPageRange
, &page_range_array
) &&
208 !page_range_array
->empty()) {
209 ReportPrintSettingHistogram(PAGE_RANGE
);
212 const base::DictionaryValue
* media_size_value
= NULL
;
213 if (settings
.GetDictionary(printing::kSettingMediaSize
, &media_size_value
) &&
214 !media_size_value
->empty()) {
215 bool is_default
= false;
216 if (media_size_value
->GetBoolean(printing::kSettingMediaSizeIsDefault
,
219 ReportPrintSettingHistogram(DEFAULT_MEDIA
);
221 ReportPrintSettingHistogram(NON_DEFAULT_MEDIA
);
225 bool landscape
= false;
226 if (settings
.GetBoolean(printing::kSettingLandscape
, &landscape
))
227 ReportPrintSettingHistogram(landscape
? LANDSCAPE
: PORTRAIT
);
230 if (settings
.GetInteger(printing::kSettingCopies
, &copies
) && copies
> 1)
231 ReportPrintSettingHistogram(COPIES
);
233 bool collate
= false;
234 if (settings
.GetBoolean(printing::kSettingCollate
, &collate
) && collate
)
235 ReportPrintSettingHistogram(COLLATE
);
238 if (settings
.GetInteger(printing::kSettingDuplexMode
, &duplex_mode
))
239 ReportPrintSettingHistogram(duplex_mode
? DUPLEX
: SIMPLEX
);
242 if (settings
.GetInteger(printing::kSettingColor
, &color_mode
)) {
243 ReportPrintSettingHistogram(
244 printing::IsColorModelSelected(color_mode
) ? COLOR
: BLACK_AND_WHITE
);
247 int margins_type
= 0;
248 if (settings
.GetInteger(printing::kSettingMarginsType
, &margins_type
) &&
250 ReportPrintSettingHistogram(NON_DEFAULT_MARGINS
);
253 bool headers
= false;
254 if (settings
.GetBoolean(printing::kSettingHeaderFooterEnabled
, &headers
) &&
256 ReportPrintSettingHistogram(HEADERS_AND_FOOTERS
);
259 bool css_background
= false;
260 if (settings
.GetBoolean(printing::kSettingShouldPrintBackgrounds
,
261 &css_background
) && css_background
) {
262 ReportPrintSettingHistogram(CSS_BACKGROUND
);
265 bool selection_only
= false;
266 if (settings
.GetBoolean(printing::kSettingShouldPrintSelectionOnly
,
267 &selection_only
) && selection_only
) {
268 ReportPrintSettingHistogram(SELECTION_ONLY
);
271 bool external_preview
= false;
272 if (settings
.GetBoolean(printing::kSettingOpenPDFInPreview
,
273 &external_preview
) && external_preview
) {
274 ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW
);
278 // Callback that stores a PDF file on disk.
279 void PrintToPdfCallback(const scoped_refptr
<base::RefCountedBytes
>& data
,
280 const base::FilePath
& path
,
281 const base::Closure
& pdf_file_saved_closure
) {
282 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
283 printing::PdfMetafileSkia metafile
;
284 metafile
.InitFromData(static_cast<const void*>(data
->front()), data
->size());
285 base::File
file(path
,
286 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_WRITE
);
287 metafile
.SaveTo(&file
);
288 if (!pdf_file_saved_closure
.is_null())
289 pdf_file_saved_closure
.Run();
292 std::string
GetDefaultPrinterOnFileThread() {
293 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
295 scoped_refptr
<printing::PrintBackend
> print_backend(
296 printing::PrintBackend::CreateInstance(NULL
));
298 std::string default_printer
= print_backend
->GetDefaultPrinterName();
299 VLOG(1) << "Default Printer: " << default_printer
;
300 return default_printer
;
303 class PrintingContextDelegate
: public printing::PrintingContext::Delegate
{
305 // PrintingContext::Delegate methods.
306 gfx::NativeView
GetParentView() override
{ return NULL
; }
307 std::string
GetAppLocale() override
{
308 return g_browser_process
->GetApplicationLocale();
312 gfx::Size
GetDefaultPdfMediaSizeMicrons() {
313 PrintingContextDelegate delegate
;
314 scoped_ptr
<printing::PrintingContext
> printing_context(
315 printing::PrintingContext::Create(&delegate
));
316 if (printing::PrintingContext::OK
!= printing_context
->UsePdfSettings() ||
317 printing_context
->settings().device_units_per_inch() <= 0) {
320 gfx::Size pdf_media_size
= printing_context
->GetPdfPaperSizeDeviceUnits();
321 float deviceMicronsPerDeviceUnit
=
322 (printing::kHundrethsMMPerInch
* 10.0f
) /
323 printing_context
->settings().device_units_per_inch();
324 return gfx::Size(pdf_media_size
.width() * deviceMicronsPerDeviceUnit
,
325 pdf_media_size
.height() * deviceMicronsPerDeviceUnit
);
328 typedef base::Callback
<void(const base::DictionaryValue
*)>
329 GetPdfCapabilitiesCallback
;
331 scoped_ptr
<base::DictionaryValue
> GetPdfCapabilitiesOnFileThread(
332 const std::string
& locale
) {
333 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
335 cloud_devices::CloudDeviceDescription description
;
336 using namespace cloud_devices::printer
;
338 OrientationCapability orientation
;
339 orientation
.AddOption(cloud_devices::printer::PORTRAIT
);
340 orientation
.AddOption(cloud_devices::printer::LANDSCAPE
);
341 orientation
.AddDefaultOption(AUTO_ORIENTATION
, true);
342 orientation
.SaveTo(&description
);
344 ColorCapability color
;
346 Color
standard_color(STANDARD_COLOR
);
347 standard_color
.vendor_id
= base::IntToString(printing::COLOR
);
348 color
.AddDefaultOption(standard_color
, true);
350 color
.SaveTo(&description
);
352 static const cloud_devices::printer::MediaType kPdfMedia
[] = {
359 const gfx::Size default_media_size
= GetDefaultPdfMediaSizeMicrons();
361 "", "", default_media_size
.width(), default_media_size
.height());
362 if (!default_media
.MatchBySize() ||
364 kPdfMedia
+ arraysize(kPdfMedia
),
365 default_media
.type
) == kPdfMedia
+ arraysize(kPdfMedia
)) {
366 default_media
= Media(locale
== "en-US" ? NA_LETTER
: ISO_A4
);
368 MediaCapability media
;
369 for (size_t i
= 0; i
< arraysize(kPdfMedia
); ++i
) {
370 Media
media_option(kPdfMedia
[i
]);
371 media
.AddDefaultOption(media_option
,
372 default_media
.type
== media_option
.type
);
374 media
.SaveTo(&description
);
376 return scoped_ptr
<base::DictionaryValue
>(description
.root().DeepCopy());
379 scoped_ptr
<base::DictionaryValue
> GetLocalPrinterCapabilitiesOnFileThread(
380 const std::string
& printer_name
) {
381 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
383 scoped_refptr
<printing::PrintBackend
> print_backend(
384 printing::PrintBackend::CreateInstance(NULL
));
386 VLOG(1) << "Get printer capabilities start for " << printer_name
;
387 crash_keys::ScopedPrinterInfo
crash_key(
388 print_backend
->GetPrinterDriverInfo(printer_name
));
390 if (!print_backend
->IsValidPrinter(printer_name
)) {
391 LOG(WARNING
) << "Invalid printer " << printer_name
;
392 return scoped_ptr
<base::DictionaryValue
>();
395 printing::PrinterSemanticCapsAndDefaults info
;
396 if (!print_backend
->GetPrinterSemanticCapsAndDefaults(printer_name
, &info
)) {
397 LOG(WARNING
) << "Failed to get capabilities for " << printer_name
;
398 return scoped_ptr
<base::DictionaryValue
>();
401 scoped_ptr
<base::DictionaryValue
> description(
402 cloud_print::PrinterSemanticCapsAndDefaultsToCdd(info
));
404 LOG(WARNING
) << "Failed to convert capabilities for " << printer_name
;
405 return scoped_ptr
<base::DictionaryValue
>();
408 return description
.Pass();
411 void EnumeratePrintersOnFileThread(base::ListValue
* printers
) {
412 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
414 scoped_refptr
<printing::PrintBackend
> print_backend(
415 printing::PrintBackend::CreateInstance(NULL
));
417 VLOG(1) << "Enumerate printers start";
418 printing::PrinterList printer_list
;
419 print_backend
->EnumeratePrinters(&printer_list
);
421 for (printing::PrinterList::iterator it
= printer_list
.begin();
422 it
!= printer_list
.end(); ++it
) {
423 base::DictionaryValue
* printer_info
= new base::DictionaryValue
;
424 printers
->Append(printer_info
);
425 std::string printer_name
;
426 std::string printer_description
;
427 #if defined(OS_MACOSX)
428 // On Mac, |it->printer_description| specifies the printer name and
429 // |it->printer_name| specifies the device name / printer queue name.
430 printer_name
= it
->printer_description
;
431 if (!it
->options
[kDriverNameTagName
].empty())
432 printer_description
= it
->options
[kDriverNameTagName
];
434 printer_name
= it
->printer_name
;
435 printer_description
= it
->printer_description
;
437 printer_info
->SetString(printing::kSettingDeviceName
, it
->printer_name
);
438 printer_info
->SetString(printing::kSettingPrinterDescription
,
439 printer_description
);
440 printer_info
->SetString(printing::kSettingPrinterName
, printer_name
);
441 VLOG(1) << "Found printer " << printer_name
442 << " with device name " << it
->printer_name
;
444 base::DictionaryValue
* options
= new base::DictionaryValue
;
445 printer_info
->Set(printing::kSettingPrinterOptions
, options
);
446 for (std::map
<std::string
, std::string
>::iterator opt
= it
->options
.begin();
447 opt
!= it
->options
.end();
449 options
->SetString(opt
->first
, opt
->second
);
452 VLOG(1) << "Found printer " << printer_name
<< " with device name "
455 VLOG(1) << "Enumerate printers finished, found " << printers
->GetSize()
459 typedef base::Callback
<void(const base::DictionaryValue
*)>
460 GetPrinterCapabilitiesSuccessCallback
;
461 typedef base::Callback
<void(const std::string
&)>
462 GetPrinterCapabilitiesFailureCallback
;
464 void GetPrinterCapabilitiesOnFileThread(
465 const std::string
& printer_name
,
466 const std::string
& locale
,
467 const GetPrinterCapabilitiesSuccessCallback
& success_cb
,
468 const GetPrinterCapabilitiesFailureCallback
& failure_cb
) {
469 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
470 DCHECK(!printer_name
.empty());
472 scoped_ptr
<base::DictionaryValue
> printer_capabilities(
473 printer_name
== kLocalPdfPrinterId
?
474 GetPdfCapabilitiesOnFileThread(locale
) :
475 GetLocalPrinterCapabilitiesOnFileThread(printer_name
));
476 if (!printer_capabilities
) {
477 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
478 base::Bind(failure_cb
, printer_name
));
482 scoped_ptr
<base::DictionaryValue
> printer_info(new base::DictionaryValue
);
483 printer_info
->SetString(kPrinterId
, printer_name
);
484 printer_info
->Set(kPrinterCapabilities
, printer_capabilities
.release());
486 BrowserThread::PostTask(
487 BrowserThread::UI
, FROM_HERE
,
488 base::Bind(success_cb
, base::Owned(printer_info
.release())));
491 base::LazyInstance
<printing::StickySettings
> g_sticky_settings
=
492 LAZY_INSTANCE_INITIALIZER
;
494 printing::StickySettings
* GetStickySettings() {
495 return g_sticky_settings
.Pointer();
500 class PrintPreviewHandler::AccessTokenService
501 : public OAuth2TokenService::Consumer
{
503 explicit AccessTokenService(PrintPreviewHandler
* handler
)
504 : OAuth2TokenService::Consumer("print_preview"),
508 void RequestToken(const std::string
& type
) {
509 if (requests_
.find(type
) != requests_
.end())
510 return; // Already in progress.
512 OAuth2TokenService
* service
= NULL
;
513 std::string account_id
;
514 if (type
== "profile") {
515 Profile
* profile
= Profile::FromWebUI(handler_
->web_ui());
517 ProfileOAuth2TokenService
* token_service
=
518 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
);
519 SigninManagerBase
* signin_manager
=
520 SigninManagerFactory::GetInstance()->GetForProfile(profile
);
521 account_id
= signin_manager
->GetAuthenticatedAccountId();
522 service
= token_service
;
524 } else if (type
== "device") {
525 #if defined(OS_CHROMEOS)
526 chromeos::DeviceOAuth2TokenService
* token_service
=
527 chromeos::DeviceOAuth2TokenServiceFactory::Get();
528 account_id
= token_service
->GetRobotAccountId();
529 service
= token_service
;
534 OAuth2TokenService::ScopeSet oauth_scopes
;
535 oauth_scopes
.insert(cloud_devices::kCloudPrintAuthScope
);
536 scoped_ptr
<OAuth2TokenService::Request
> request(
537 service
->StartRequest(account_id
, oauth_scopes
, this));
538 requests_
[type
].reset(request
.release());
540 handler_
->SendAccessToken(type
, std::string()); // Unknown type.
544 void OnGetTokenSuccess(const OAuth2TokenService::Request
* request
,
545 const std::string
& access_token
,
546 const base::Time
& expiration_time
) override
{
547 OnServiceResponce(request
, access_token
);
550 void OnGetTokenFailure(const OAuth2TokenService::Request
* request
,
551 const GoogleServiceAuthError
& error
) override
{
552 OnServiceResponce(request
, std::string());
556 void OnServiceResponce(const OAuth2TokenService::Request
* request
,
557 const std::string
& access_token
) {
558 for (Requests::iterator i
= requests_
.begin(); i
!= requests_
.end(); ++i
) {
559 if (i
->second
== request
) {
560 handler_
->SendAccessToken(i
->first
, access_token
);
568 typedef std::map
<std::string
,
569 linked_ptr
<OAuth2TokenService::Request
> > Requests
;
571 PrintPreviewHandler
* handler_
;
573 DISALLOW_COPY_AND_ASSIGN(AccessTokenService
);
576 PrintPreviewHandler::PrintPreviewHandler()
577 : regenerate_preview_request_count_(0),
578 manage_printers_dialog_request_count_(0),
579 manage_cloud_printers_dialog_request_count_(0),
580 reported_failed_preview_(false),
581 has_logged_printers_count_(false),
583 weak_factory_(this) {
584 ReportUserActionHistogram(PREVIEW_STARTED
);
587 PrintPreviewHandler::~PrintPreviewHandler() {
588 if (select_file_dialog_
.get())
589 select_file_dialog_
->ListenerDestroyed();
591 UnregisterForMergeSession();
594 void PrintPreviewHandler::RegisterMessages() {
595 web_ui()->RegisterMessageCallback("getPrinters",
596 base::Bind(&PrintPreviewHandler::HandleGetPrinters
,
597 base::Unretained(this)));
598 web_ui()->RegisterMessageCallback("getPreview",
599 base::Bind(&PrintPreviewHandler::HandleGetPreview
,
600 base::Unretained(this)));
601 web_ui()->RegisterMessageCallback("print",
602 base::Bind(&PrintPreviewHandler::HandlePrint
,
603 base::Unretained(this)));
604 web_ui()->RegisterMessageCallback("getPrinterCapabilities",
605 base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities
,
606 base::Unretained(this)));
607 #if defined(ENABLE_BASIC_PRINTING)
608 web_ui()->RegisterMessageCallback("showSystemDialog",
609 base::Bind(&PrintPreviewHandler::HandleShowSystemDialog
,
610 base::Unretained(this)));
611 #endif // ENABLE_BASIC_PRINTING
612 web_ui()->RegisterMessageCallback("signIn",
613 base::Bind(&PrintPreviewHandler::HandleSignin
,
614 base::Unretained(this)));
615 web_ui()->RegisterMessageCallback("getAccessToken",
616 base::Bind(&PrintPreviewHandler::HandleGetAccessToken
,
617 base::Unretained(this)));
618 web_ui()->RegisterMessageCallback("manageCloudPrinters",
619 base::Bind(&PrintPreviewHandler::HandleManageCloudPrint
,
620 base::Unretained(this)));
621 web_ui()->RegisterMessageCallback("manageLocalPrinters",
622 base::Bind(&PrintPreviewHandler::HandleManagePrinters
,
623 base::Unretained(this)));
624 web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
625 base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog
,
626 base::Unretained(this)));
627 web_ui()->RegisterMessageCallback("hidePreview",
628 base::Bind(&PrintPreviewHandler::HandleHidePreview
,
629 base::Unretained(this)));
630 web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
631 base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest
,
632 base::Unretained(this)));
633 web_ui()->RegisterMessageCallback("saveAppState",
634 base::Bind(&PrintPreviewHandler::HandleSaveAppState
,
635 base::Unretained(this)));
636 web_ui()->RegisterMessageCallback("getInitialSettings",
637 base::Bind(&PrintPreviewHandler::HandleGetInitialSettings
,
638 base::Unretained(this)));
639 web_ui()->RegisterMessageCallback("forceOpenNewTab",
640 base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab
,
641 base::Unretained(this)));
642 web_ui()->RegisterMessageCallback("getPrivetPrinters",
643 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters
,
644 base::Unretained(this)));
645 web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
646 base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters
,
647 base::Unretained(this)));
648 web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
649 base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities
,
650 base::Unretained(this)));
651 web_ui()->RegisterMessageCallback(
652 "getExtensionPrinters",
653 base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinters
,
654 base::Unretained(this)));
655 web_ui()->RegisterMessageCallback(
656 "getExtensionPrinterCapabilities",
657 base::Bind(&PrintPreviewHandler::HandleGetExtensionPrinterCapabilities
,
658 base::Unretained(this)));
659 RegisterForMergeSession();
662 bool PrintPreviewHandler::PrivetPrintingEnabled() {
663 #if defined(ENABLE_SERVICE_DISCOVERY)
670 WebContents
* PrintPreviewHandler::preview_web_contents() const {
671 return web_ui()->GetWebContents();
674 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue
* /*args*/) {
675 base::ListValue
* results
= new base::ListValue
;
676 BrowserThread::PostTaskAndReply(
677 BrowserThread::FILE, FROM_HERE
,
678 base::Bind(&EnumeratePrintersOnFileThread
,
679 base::Unretained(results
)),
680 base::Bind(&PrintPreviewHandler::SetupPrinterList
,
681 weak_factory_
.GetWeakPtr(),
682 base::Owned(results
)));
685 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue
* args
) {
686 if (!PrivetPrintingEnabled())
687 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
688 #if defined(ENABLE_SERVICE_DISCOVERY)
689 local_discovery::ServiceDiscoverySharedClient::GetInstanceWithoutAlert(
690 base::Bind(&PrintPreviewHandler::StartPrivetLister
,
691 weak_factory_
.GetWeakPtr()));
692 #endif // ENABLE_SERVICE_DISCOVERY
695 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
696 const base::ListValue
* args
) {
697 #if defined(ENABLE_SERVICE_DISCOVERY)
698 if (PrivetPrintingEnabled() && printer_lister_
) {
699 printer_lister_
->Stop();
704 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
705 const base::ListValue
* args
) {
706 #if defined(ENABLE_SERVICE_DISCOVERY)
708 bool success
= args
->GetString(0, &name
);
713 base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient
,
714 base::Unretained(this)));
718 void PrintPreviewHandler::HandleGetExtensionPrinters(
719 const base::ListValue
* args
) {
720 EnsureExtensionPrinterHandlerSet();
721 // Make sure all in progress requests are canceled before new printer search
723 extension_printer_handler_
->Reset();
724 extension_printer_handler_
->StartGetPrinters(base::Bind(
725 &PrintPreviewHandler::OnGotPrintersForExtension
, base::Unretained(this)));
728 void PrintPreviewHandler::HandleGetExtensionPrinterCapabilities(
729 const base::ListValue
* args
) {
730 std::string printer_id
;
731 bool ok
= args
->GetString(0, &printer_id
);
734 EnsureExtensionPrinterHandlerSet();
735 extension_printer_handler_
->StartGetCapability(
737 base::Bind(&PrintPreviewHandler::OnGotExtensionPrinterCapabilities
,
738 base::Unretained(this)));
741 void PrintPreviewHandler::HandleGetPreview(const base::ListValue
* args
) {
742 DCHECK_EQ(3U, args
->GetSize());
743 scoped_ptr
<base::DictionaryValue
> settings(GetSettingsDictionary(args
));
747 if (!settings
->GetInteger(printing::kPreviewRequestID
, &request_id
))
750 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
751 web_ui()->GetController());
752 print_preview_ui
->OnPrintPreviewRequest(request_id
);
753 // Add an additional key in order to identify |print_preview_ui| later on
754 // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
756 settings
->SetInteger(printing::kPreviewUIID
,
757 print_preview_ui
->GetIDForPrintPreviewUI());
759 // Increment request count.
760 ++regenerate_preview_request_count_
;
762 WebContents
* initiator
= GetInitiator();
764 ReportUserActionHistogram(INITIATOR_CLOSED
);
765 print_preview_ui
->OnClosePrintPreviewDialog();
769 // Retrieve the page title and url and send it to the renderer process if
770 // headers and footers are to be displayed.
771 bool display_header_footer
= false;
772 if (!settings
->GetBoolean(printing::kSettingHeaderFooterEnabled
,
773 &display_header_footer
)) {
776 if (display_header_footer
) {
777 settings
->SetString(printing::kSettingHeaderFooterTitle
,
778 initiator
->GetTitle());
780 content::NavigationEntry
* entry
=
781 initiator
->GetController().GetLastCommittedEntry();
783 url
= entry
->GetVirtualURL().spec();
784 settings
->SetString(printing::kSettingHeaderFooterURL
, url
);
787 bool generate_draft_data
= false;
788 bool success
= settings
->GetBoolean(printing::kSettingGenerateDraftData
,
789 &generate_draft_data
);
792 if (!generate_draft_data
) {
793 double draft_page_count_double
= -1;
794 success
= args
->GetDouble(1, &draft_page_count_double
);
796 int draft_page_count
= static_cast<int>(draft_page_count_double
);
798 bool preview_modifiable
= false;
799 success
= args
->GetBoolean(2, &preview_modifiable
);
802 if (draft_page_count
!= -1 && preview_modifiable
&&
803 print_preview_ui
->GetAvailableDraftPageCount() != draft_page_count
) {
804 settings
->SetBoolean(printing::kSettingGenerateDraftData
, true);
808 VLOG(1) << "Print preview request start";
809 RenderViewHost
* rvh
= initiator
->GetRenderViewHost();
810 rvh
->Send(new PrintMsg_PrintPreview(rvh
->GetRoutingID(), *settings
));
813 void PrintPreviewHandler::HandlePrint(const base::ListValue
* args
) {
816 // Record the number of times the user requests to regenerate preview data
818 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
819 regenerate_preview_request_count_
);
821 scoped_ptr
<base::DictionaryValue
> settings(GetSettingsDictionary(args
));
825 ReportPrintSettingsStats(*settings
);
827 // Never try to add headers/footers here. It's already in the generated PDF.
828 settings
->SetBoolean(printing::kSettingHeaderFooterEnabled
, false);
830 bool print_to_pdf
= false;
831 bool is_cloud_printer
= false;
832 bool print_with_privet
= false;
833 bool print_with_extension
= false;
835 bool open_pdf_in_preview
= false;
836 #if defined(OS_MACOSX)
837 open_pdf_in_preview
= settings
->HasKey(printing::kSettingOpenPDFInPreview
);
840 if (!open_pdf_in_preview
) {
841 settings
->GetBoolean(printing::kSettingPrintToPDF
, &print_to_pdf
);
842 settings
->GetBoolean(printing::kSettingPrintWithPrivet
, &print_with_privet
);
843 settings
->GetBoolean(printing::kSettingPrintWithExtension
,
844 &print_with_extension
);
845 is_cloud_printer
= settings
->HasKey(printing::kSettingCloudPrintId
);
849 settings
->GetInteger(printing::kSettingPreviewPageCount
, &page_count
);
852 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count
);
853 ReportUserActionHistogram(PRINT_TO_PDF
);
858 #if defined(ENABLE_SERVICE_DISCOVERY)
859 if (print_with_privet
&& PrivetPrintingEnabled()) {
860 std::string printer_name
;
861 std::string print_ticket
;
862 std::string capabilities
;
863 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count
);
864 ReportUserActionHistogram(PRINT_WITH_PRIVET
);
868 if (!settings
->GetString(printing::kSettingDeviceName
, &printer_name
) ||
869 !settings
->GetString(printing::kSettingTicket
, &print_ticket
) ||
870 !settings
->GetString(printing::kSettingCapabilities
, &capabilities
) ||
871 !settings
->GetInteger(printing::kSettingPageWidth
, &width
) ||
872 !settings
->GetInteger(printing::kSettingPageHeight
, &height
) ||
873 width
<= 0 || height
<= 0) {
875 base::FundamentalValue
http_code_value(-1);
876 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
880 PrintToPrivetPrinter(
881 printer_name
, print_ticket
, capabilities
, gfx::Size(width
, height
));
886 if (print_with_extension
) {
887 // TODO(tbarzic): Record UMA stats.
889 base::string16 title
;
890 scoped_refptr
<base::RefCountedBytes
> data
;
891 if (!GetPreviewDataAndTitle(&data
, &title
)) {
892 LOG(ERROR
) << "Nothing to print; no preview available.";
893 OnExtensionPrintResult(false, "NO_DATA");
897 EnsureExtensionPrinterHandlerSet();
898 extension_printer_handler_
->StartPrint(
900 base::Bind(&PrintPreviewHandler::OnExtensionPrintResult
,
901 base::Unretained(this)));
905 scoped_refptr
<base::RefCountedBytes
> data
;
906 base::string16 title
;
907 if (!GetPreviewDataAndTitle(&data
, &title
)) {
908 // Nothing to print, no preview available.
912 if (is_cloud_printer
) {
913 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
915 ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT
);
916 SendCloudPrintJob(data
.get());
918 bool system_dialog
= false;
919 settings
->GetBoolean(printing::kSettingShowSystemDialog
, &system_dialog
);
921 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count
);
922 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
);
924 UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count
);
925 ReportUserActionHistogram(PRINT_TO_PRINTER
);
928 // This tries to activate the initiator as well, so do not clear the
929 // association with the initiator yet.
930 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
931 web_ui()->GetController());
932 print_preview_ui
->OnHidePreviewDialog();
934 // Do this so the initiator can open a new print preview dialog, while the
935 // current print preview dialog is still handling its print job.
936 WebContents
* initiator
= GetInitiator();
938 // Save initiator IDs. |PrintingMessageFilter::OnUpdatePrintSettings|
939 // would be called when initiator info is cleared.
940 settings
->SetInteger(printing::kPreviewInitiatorHostId
,
941 initiator
->GetRenderProcessHost()->GetID());
942 settings
->SetInteger(printing::kPreviewInitiatorRoutingId
,
943 initiator
->GetRoutingID());
946 ClearInitiatorDetails();
948 // The PDF being printed contains only the pages that the user selected,
949 // so ignore the page range and print all pages.
950 settings
->Remove(printing::kSettingPageRange
, NULL
);
951 // Reset selection only flag for the same reason.
952 settings
->SetBoolean(printing::kSettingShouldPrintSelectionOnly
, false);
954 // Set ID to know whether printing is for preview.
955 settings
->SetInteger(printing::kPreviewUIID
,
956 print_preview_ui
->GetIDForPrintPreviewUI());
957 RenderViewHost
* rvh
= preview_web_contents()->GetRenderViewHost();
958 rvh
->Send(new PrintMsg_PrintForPrintPreview(rvh
->GetRoutingID(),
961 // For all other cases above, the preview dialog will stay open until the
962 // printing has finished. Then the dialog closes and PrintPreviewDone() gets
963 // called. In the case below, since the preview dialog will be hidden and
964 // not closed, we need to make this call.
966 printing::PrintViewManager
* print_view_manager
=
967 printing::PrintViewManager::FromWebContents(initiator
);
968 print_view_manager
->PrintPreviewDone();
973 void PrintPreviewHandler::PrintToPdf() {
974 if (!print_to_pdf_path_
.empty()) {
975 // User has already selected a path, no need to show the dialog again.
976 PostPrintToPdfTask();
977 } else if (!select_file_dialog_
.get() ||
978 !select_file_dialog_
->IsRunning(platform_util::GetTopLevel(
979 preview_web_contents()->GetNativeView()))) {
980 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
981 web_ui()->GetController());
982 // Pre-populating select file dialog with print job title.
983 base::string16 print_job_title_utf16
= print_preview_ui
->initiator_title();
986 base::FilePath::StringType
print_job_title(print_job_title_utf16
);
987 #elif defined(OS_POSIX)
988 base::FilePath::StringType print_job_title
=
989 base::UTF16ToUTF8(print_job_title_utf16
);
992 base::i18n::ReplaceIllegalCharactersInPath(&print_job_title
, '_');
993 base::FilePath
default_filename(print_job_title
);
995 default_filename
.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
997 SelectFile(default_filename
);
1001 void PrintPreviewHandler::HandleHidePreview(const base::ListValue
* /*args*/) {
1002 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
1003 web_ui()->GetController());
1004 print_preview_ui
->OnHidePreviewDialog();
1007 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
1008 const base::ListValue
* /*args*/) {
1009 WebContents
* initiator
= GetInitiator();
1011 ClearInitiatorDetails();
1012 chrome::ShowPrintErrorDialog();
1015 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue
* args
) {
1016 std::string data_to_save
;
1017 printing::StickySettings
* sticky_settings
= GetStickySettings();
1018 if (args
->GetString(0, &data_to_save
) && !data_to_save
.empty())
1019 sticky_settings
->StoreAppState(data_to_save
);
1020 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
1021 preview_web_contents()->GetBrowserContext())->GetPrefs());
1024 void PrintPreviewHandler::HandleGetPrinterCapabilities(
1025 const base::ListValue
* args
) {
1026 std::string printer_name
;
1027 bool ret
= args
->GetString(0, &printer_name
);
1028 if (!ret
|| printer_name
.empty())
1031 GetPrinterCapabilitiesSuccessCallback success_cb
=
1032 base::Bind(&PrintPreviewHandler::SendPrinterCapabilities
,
1033 weak_factory_
.GetWeakPtr());
1034 GetPrinterCapabilitiesFailureCallback failure_cb
=
1035 base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities
,
1036 weak_factory_
.GetWeakPtr());
1037 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE
,
1038 base::Bind(&GetPrinterCapabilitiesOnFileThread
,
1040 g_browser_process
->GetApplicationLocale(),
1041 success_cb
, failure_cb
));
1044 void PrintPreviewHandler::OnSigninComplete() {
1045 PrintPreviewUI
* print_preview_ui
=
1046 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
1047 if (print_preview_ui
)
1048 print_preview_ui
->OnReloadPrintersList();
1051 void PrintPreviewHandler::HandleSignin(const base::ListValue
* args
) {
1052 bool add_account
= false;
1053 bool success
= args
->GetBoolean(0, &add_account
);
1056 Profile
* profile
= Profile::FromBrowserContext(
1057 preview_web_contents()->GetBrowserContext());
1058 chrome::ScopedTabbedBrowserDisplayer
displayer(
1059 profile
, chrome::GetActiveDesktop());
1060 print_dialog_cloud::CreateCloudPrintSigninTab(
1061 displayer
.browser(),
1063 base::Bind(&PrintPreviewHandler::OnSigninComplete
,
1064 weak_factory_
.GetWeakPtr()));
1067 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue
* args
) {
1069 if (!args
->GetString(0, &type
))
1071 if (!token_service_
)
1072 token_service_
.reset(new AccessTokenService(this));
1073 token_service_
->RequestToken(type
);
1076 void PrintPreviewHandler::HandleManageCloudPrint(
1077 const base::ListValue
* args
) {
1078 ++manage_cloud_printers_dialog_request_count_
;
1079 GURL
manage_url(cloud_devices::GetCloudPrintRelativeURL("manage.html"));
1081 if (!args
->GetString(0, &user
))
1084 manage_url
= net::AppendQueryParameter(manage_url
, "user", user
);
1085 preview_web_contents()->OpenURL(content::OpenURLParams(
1087 content::Referrer(),
1089 ui::PAGE_TRANSITION_LINK
,
1093 #if defined(ENABLE_BASIC_PRINTING)
1094 void PrintPreviewHandler::HandleShowSystemDialog(
1095 const base::ListValue
* /*args*/) {
1097 ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG
);
1099 WebContents
* initiator
= GetInitiator();
1103 printing::PrintViewManager
* print_view_manager
=
1104 printing::PrintViewManager::FromWebContents(initiator
);
1105 print_view_manager
->set_observer(this);
1106 print_view_manager
->PrintForSystemDialogNow();
1108 // Cancel the pending preview request if exists.
1109 PrintPreviewUI
* print_preview_ui
=
1110 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
1111 print_preview_ui
->OnCancelPendingPreviewRequest();
1113 #endif // ENABLE_BASIC_PRINTING
1115 void PrintPreviewHandler::HandleManagePrinters(
1116 const base::ListValue
* /*args*/) {
1117 ++manage_printers_dialog_request_count_
;
1118 printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1121 void PrintPreviewHandler::HandleClosePreviewDialog(
1122 const base::ListValue
* /*args*/) {
1124 ReportUserActionHistogram(CANCEL
);
1126 // Record the number of times the user requests to regenerate preview data
1127 // before cancelling.
1128 UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1129 regenerate_preview_request_count_
);
1132 void PrintPreviewHandler::ReportStats() {
1133 UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1134 manage_printers_dialog_request_count_
);
1135 UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1136 manage_cloud_printers_dialog_request_count_
);
1139 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1140 base::DictionaryValue
* settings
) {
1142 // Getting the measurement system based on the locale.
1143 UErrorCode errorCode
= U_ZERO_ERROR
;
1144 const char* locale
= g_browser_process
->GetApplicationLocale().c_str();
1145 UMeasurementSystem system
= ulocdata_getMeasurementSystem(locale
, &errorCode
);
1146 if (errorCode
> U_ZERO_ERROR
|| system
== UMS_LIMIT
)
1149 // Getting the number formatting based on the locale and writing to
1151 settings
->SetString(kNumberFormat
, base::FormatDouble(123456.78, 2));
1152 settings
->SetInteger(kMeasurementSystem
, system
);
1155 void PrintPreviewHandler::HandleGetInitialSettings(
1156 const base::ListValue
* /*args*/) {
1157 // Send before SendInitialSettings to allow cloud printer auto select.
1158 SendCloudPrintEnabled();
1159 BrowserThread::PostTaskAndReplyWithResult(
1160 BrowserThread::FILE, FROM_HERE
,
1161 base::Bind(&GetDefaultPrinterOnFileThread
),
1162 base::Bind(&PrintPreviewHandler::SendInitialSettings
,
1163 weak_factory_
.GetWeakPtr()));
1166 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue
* args
) {
1168 if (!args
->GetString(0, &url
))
1170 Browser
* browser
= chrome::FindBrowserWithWebContents(GetInitiator());
1173 chrome::AddSelectedTabWithURL(browser
,
1175 ui::PAGE_TRANSITION_LINK
);
1178 void PrintPreviewHandler::SendInitialSettings(
1179 const std::string
& default_printer
) {
1180 PrintPreviewUI
* print_preview_ui
=
1181 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
1183 base::DictionaryValue initial_settings
;
1184 initial_settings
.SetString(kInitiatorTitle
,
1185 print_preview_ui
->initiator_title());
1186 initial_settings
.SetBoolean(printing::kSettingPreviewModifiable
,
1187 print_preview_ui
->source_is_modifiable());
1188 initial_settings
.SetString(printing::kSettingPrinterName
, default_printer
);
1189 initial_settings
.SetBoolean(kDocumentHasSelection
,
1190 print_preview_ui
->source_has_selection());
1191 initial_settings
.SetBoolean(printing::kSettingShouldPrintSelectionOnly
,
1192 print_preview_ui
->print_selection_only());
1193 printing::StickySettings
* sticky_settings
= GetStickySettings();
1194 sticky_settings
->RestoreFromPrefs(Profile::FromBrowserContext(
1195 preview_web_contents()->GetBrowserContext())->GetPrefs());
1196 if (sticky_settings
->printer_app_state()) {
1197 initial_settings
.SetString(kAppState
,
1198 *sticky_settings
->printer_app_state());
1201 base::CommandLine
* cmdline
= base::CommandLine::ForCurrentProcess();
1202 initial_settings
.SetBoolean(kPrintAutomaticallyInKioskMode
,
1203 cmdline
->HasSwitch(switches::kKioskModePrinting
));
1204 initial_settings
.SetBoolean(kAppKioskMode
,
1205 chrome::IsRunningInForcedAppMode());
1207 // In Win8 metro, the system print dialog can only open on the desktop. Doing
1208 // so will cause the browser to appear hung, so we don't show the link in
1210 bool is_ash
= (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH
);
1211 initial_settings
.SetBoolean(kHidePrintWithSystemDialogLink
, is_ash
);
1214 if (print_preview_ui
->source_is_modifiable())
1215 GetNumberFormatAndMeasurementSystem(&initial_settings
);
1216 web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings
);
1219 void PrintPreviewHandler::ClosePreviewDialog() {
1220 PrintPreviewUI
* print_preview_ui
=
1221 static_cast<PrintPreviewUI
*>(web_ui()->GetController());
1222 print_preview_ui
->OnClosePrintPreviewDialog();
1225 void PrintPreviewHandler::SendAccessToken(const std::string
& type
,
1226 const std::string
& access_token
) {
1227 VLOG(1) << "Get getAccessToken finished";
1228 web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1229 base::StringValue(type
),
1230 base::StringValue(access_token
));
1233 void PrintPreviewHandler::SendPrinterCapabilities(
1234 const base::DictionaryValue
* settings_info
) {
1235 VLOG(1) << "Get printer capabilities finished";
1236 web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1240 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1241 const std::string
& printer_name
) {
1242 VLOG(1) << "Get printer capabilities failed";
1243 base::StringValue
printer_name_value(printer_name
);
1244 web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1245 printer_name_value
);
1248 void PrintPreviewHandler::SetupPrinterList(const base::ListValue
* printers
) {
1249 if (!has_logged_printers_count_
) {
1250 UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers
->GetSize());
1251 has_logged_printers_count_
= true;
1254 web_ui()->CallJavascriptFunction("setPrinters", *printers
);
1257 void PrintPreviewHandler::SendCloudPrintEnabled() {
1258 Profile
* profile
= Profile::FromBrowserContext(
1259 preview_web_contents()->GetBrowserContext());
1260 PrefService
* prefs
= profile
->GetPrefs();
1261 if (prefs
->GetBoolean(prefs::kCloudPrintSubmitEnabled
)) {
1262 base::DictionaryValue settings
;
1263 settings
.SetString(kCloudPrintUrl
,
1264 GURL(cloud_devices::GetCloudPrintURL()).spec());
1265 settings
.SetBoolean(kAppKioskMode
, chrome::IsRunningInForcedAppMode());
1266 web_ui()->CallJavascriptFunction("setUseCloudPrint", settings
);
1270 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes
* data
) {
1271 // BASE64 encode the job data.
1272 std::string
raw_data(reinterpret_cast<const char*>(data
->front()),
1274 std::string base64_data
;
1275 base::Base64Encode(raw_data
, &base64_data
);
1276 base::StringValue
data_value(base64_data
);
1278 web_ui()->CallJavascriptFunction("printToCloud", data_value
);
1281 WebContents
* PrintPreviewHandler::GetInitiator() const {
1282 printing::PrintPreviewDialogController
* dialog_controller
=
1283 printing::PrintPreviewDialogController::GetInstance();
1284 if (!dialog_controller
)
1286 return dialog_controller
->GetInitiator(preview_web_contents());
1289 void PrintPreviewHandler::OnPrintDialogShown() {
1290 ClosePreviewDialog();
1293 void PrintPreviewHandler::MergeSessionCompleted(
1294 const std::string
& account_id
,
1295 const GoogleServiceAuthError
& error
) {
1299 void PrintPreviewHandler::SelectFile(const base::FilePath
& default_filename
) {
1300 ChromeSelectFilePolicy
policy(GetInitiator());
1301 if (!policy
.CanOpenSelectFileDialog()) {
1302 policy
.SelectFileDenied();
1303 return ClosePreviewDialog();
1306 ui::SelectFileDialog::FileTypeInfo file_type_info
;
1307 file_type_info
.extensions
.resize(1);
1308 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("pdf"));
1310 // Initializing |save_path_| if it is not already initialized.
1311 printing::StickySettings
* sticky_settings
= GetStickySettings();
1312 if (!sticky_settings
->save_path()) {
1313 // Allowing IO operation temporarily. It is ok to do so here because
1314 // the select file dialog performs IO anyway in order to display the
1315 // folders and also it is modal.
1316 base::ThreadRestrictions::ScopedAllowIO allow_io
;
1317 base::FilePath file_path
;
1318 PathService::Get(chrome::DIR_USER_DOCUMENTS
, &file_path
);
1319 sticky_settings
->StoreSavePath(file_path
);
1320 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
1321 preview_web_contents()->GetBrowserContext())->GetPrefs());
1324 select_file_dialog_
=
1325 ui::SelectFileDialog::Create(this, nullptr /*policy already checked*/);
1326 select_file_dialog_
->SelectFile(
1327 ui::SelectFileDialog::SELECT_SAVEAS_FILE
,
1329 sticky_settings
->save_path()->Append(default_filename
),
1332 base::FilePath::StringType(),
1333 platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1337 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1338 WebContents
* initiator
= GetInitiator();
1342 printing::PrintViewManager
* print_view_manager
=
1343 printing::PrintViewManager::FromWebContents(initiator
);
1344 print_view_manager
->set_observer(NULL
);
1347 void PrintPreviewHandler::OnPrintPreviewFailed() {
1348 if (reported_failed_preview_
)
1350 reported_failed_preview_
= true;
1351 ReportUserActionHistogram(PREVIEW_FAILED
);
1354 #if defined(ENABLE_BASIC_PRINTING)
1355 void PrintPreviewHandler::ShowSystemDialog() {
1356 HandleShowSystemDialog(NULL
);
1358 #endif // ENABLE_BASIC_PRINTING
1360 void PrintPreviewHandler::FileSelected(const base::FilePath
& path
,
1361 int index
, void* params
) {
1362 // Updating |save_path_| to the newly selected folder.
1363 printing::StickySettings
* sticky_settings
= GetStickySettings();
1364 sticky_settings
->StoreSavePath(path
.DirName());
1365 sticky_settings
->SaveInPrefs(Profile::FromBrowserContext(
1366 preview_web_contents()->GetBrowserContext())->GetPrefs());
1367 web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1368 print_to_pdf_path_
= path
;
1369 PostPrintToPdfTask();
1372 void PrintPreviewHandler::PostPrintToPdfTask() {
1373 scoped_refptr
<base::RefCountedBytes
> data
;
1374 base::string16 title
;
1375 if (!GetPreviewDataAndTitle(&data
, &title
)) {
1376 NOTREACHED() << "Preview data was checked before file dialog.";
1379 BrowserThread::PostTask(BrowserThread::FILE,
1381 base::Bind(&PrintToPdfCallback
,
1384 pdf_file_saved_closure_
));
1385 print_to_pdf_path_
= base::FilePath();
1386 ClosePreviewDialog();
1389 void PrintPreviewHandler::FileSelectionCanceled(void* params
) {
1390 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
1391 web_ui()->GetController());
1392 print_preview_ui
->OnFileSelectionCancelled();
1395 void PrintPreviewHandler::ClearInitiatorDetails() {
1396 WebContents
* initiator
= GetInitiator();
1400 // We no longer require the initiator details. Remove those details associated
1401 // with the preview dialog to allow the initiator to create another preview
1403 printing::PrintPreviewDialogController
* dialog_controller
=
1404 printing::PrintPreviewDialogController::GetInstance();
1405 if (dialog_controller
)
1406 dialog_controller
->EraseInitiatorInfo(preview_web_contents());
1409 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1410 scoped_refptr
<base::RefCountedBytes
>* data
,
1411 base::string16
* title
) const {
1412 PrintPreviewUI
* print_preview_ui
= static_cast<PrintPreviewUI
*>(
1413 web_ui()->GetController());
1414 scoped_refptr
<base::RefCountedBytes
> tmp_data
;
1415 print_preview_ui
->GetPrintPreviewDataForIndex(
1416 printing::COMPLETE_PREVIEW_DOCUMENT_INDEX
, &tmp_data
);
1418 if (!tmp_data
.get()) {
1419 // Nothing to print, no preview available.
1422 DCHECK(tmp_data
->size() && tmp_data
->front());
1425 *title
= print_preview_ui
->initiator_title();
1429 #if defined(ENABLE_SERVICE_DISCOVERY)
1431 void PrintPreviewHandler::StartPrivetLister(const scoped_refptr
<
1432 local_discovery::ServiceDiscoverySharedClient
>& client
) {
1433 if (!PrivetPrintingEnabled())
1434 return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1436 Profile
* profile
= Profile::FromWebUI(web_ui());
1437 DCHECK(!service_discovery_client_
.get() ||
1438 service_discovery_client_
.get() == client
.get());
1439 service_discovery_client_
= client
;
1440 printer_lister_
.reset(new local_discovery::PrivetLocalPrinterLister(
1441 service_discovery_client_
.get(), profile
->GetRequestContext(), this));
1442 printer_lister_
->Start();
1445 void PrintPreviewHandler::LocalPrinterChanged(
1447 const std::string
& name
,
1448 bool has_local_printing
,
1449 const local_discovery::DeviceDescription
& description
) {
1450 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
1451 if (has_local_printing
||
1452 command_line
->HasSwitch(switches::kEnablePrintPreviewRegisterPromos
)) {
1453 base::DictionaryValue info
;
1454 FillPrinterDescription(name
, description
, has_local_printing
, &info
);
1455 web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info
);
1459 void PrintPreviewHandler::LocalPrinterRemoved(const std::string
& name
) {
1462 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1465 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1466 scoped_ptr
<local_discovery::PrivetHTTPClient
> http_client
) {
1467 if (!PrivetUpdateClient(http_client
.Pass()))
1470 privet_capabilities_operation_
=
1471 privet_http_client_
->CreateCapabilitiesOperation(
1472 base::Bind(&PrintPreviewHandler::OnPrivetCapabilities
,
1473 base::Unretained(this)));
1474 privet_capabilities_operation_
->Start();
1477 bool PrintPreviewHandler::PrivetUpdateClient(
1478 scoped_ptr
<local_discovery::PrivetHTTPClient
> http_client
) {
1480 SendPrivetCapabilitiesError(privet_http_resolution_
->GetName());
1481 privet_http_resolution_
.reset();
1485 privet_local_print_operation_
.reset();
1486 privet_capabilities_operation_
.reset();
1487 privet_http_client_
=
1488 local_discovery::PrivetV1HTTPClient::CreateDefault(http_client
.Pass());
1490 privet_http_resolution_
.reset();
1495 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1496 std::string print_ticket
,
1497 std::string capabilities
,
1498 gfx::Size page_size
,
1499 scoped_ptr
<local_discovery::PrivetHTTPClient
> http_client
) {
1500 if (!PrivetUpdateClient(http_client
.Pass()))
1503 StartPrivetLocalPrint(print_ticket
, capabilities
, page_size
);
1506 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string
& print_ticket
,
1507 const std::string
& capabilities
,
1508 const gfx::Size
& page_size
) {
1509 privet_local_print_operation_
=
1510 privet_http_client_
->CreateLocalPrintOperation(this);
1512 privet_local_print_operation_
->SetTicket(print_ticket
);
1513 privet_local_print_operation_
->SetCapabilities(capabilities
);
1515 scoped_refptr
<base::RefCountedBytes
> data
;
1516 base::string16 title
;
1518 if (!GetPreviewDataAndTitle(&data
, &title
)) {
1519 base::FundamentalValue
http_code_value(-1);
1520 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
1524 privet_local_print_operation_
->SetJobname(base::UTF16ToUTF8(title
));
1525 privet_local_print_operation_
->SetPageSize(page_size
);
1526 privet_local_print_operation_
->SetData(data
.get());
1528 Profile
* profile
= Profile::FromWebUI(web_ui());
1529 SigninManagerBase
* signin_manager
=
1530 SigninManagerFactory::GetForProfileIfExists(profile
);
1532 if (signin_manager
) {
1533 privet_local_print_operation_
->SetUsername(
1534 signin_manager
->GetAuthenticatedUsername());
1537 privet_local_print_operation_
->Start();
1541 void PrintPreviewHandler::OnPrivetCapabilities(
1542 const base::DictionaryValue
* capabilities
) {
1543 std::string name
= privet_capabilities_operation_
->GetHTTPClient()->GetName();
1545 if (!capabilities
|| capabilities
->HasKey(local_discovery::kPrivetKeyError
) ||
1547 SendPrivetCapabilitiesError(name
);
1551 base::DictionaryValue printer_info
;
1552 const local_discovery::DeviceDescription
* description
=
1553 printer_lister_
->GetDeviceDescription(name
);
1556 SendPrivetCapabilitiesError(name
);
1560 FillPrinterDescription(name
, *description
, true, &printer_info
);
1562 web_ui()->CallJavascriptFunction(
1563 "onPrivetCapabilitiesSet",
1567 privet_capabilities_operation_
.reset();
1570 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1571 const std::string
& device_name
) {
1572 base::StringValue
name_value(device_name
);
1573 web_ui()->CallJavascriptFunction(
1574 "failedToGetPrivetPrinterCapabilities",
1578 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string
& device_name
,
1579 const std::string
& ticket
,
1580 const std::string
& capabilities
,
1581 const gfx::Size
& page_size
) {
1584 base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient
,
1585 base::Unretained(this),
1591 bool PrintPreviewHandler::CreatePrivetHTTP(
1592 const std::string
& name
,
1593 const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback
&
1595 const local_discovery::DeviceDescription
* device_description
=
1596 printer_lister_
? printer_lister_
->GetDeviceDescription(name
) : NULL
;
1598 if (!device_description
) {
1599 SendPrivetCapabilitiesError(name
);
1603 privet_http_factory_
=
1604 local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1605 service_discovery_client_
.get(),
1606 Profile::FromWebUI(web_ui())->GetRequestContext());
1607 privet_http_resolution_
= privet_http_factory_
->CreatePrivetHTTP(
1608 name
, device_description
->address
, callback
);
1609 privet_http_resolution_
->Start();
1614 void PrintPreviewHandler::OnPrivetPrintingDone(
1615 const local_discovery::PrivetLocalPrintOperation
* print_operation
) {
1616 ClosePreviewDialog();
1619 void PrintPreviewHandler::OnPrivetPrintingError(
1620 const local_discovery::PrivetLocalPrintOperation
* print_operation
,
1622 base::FundamentalValue
http_code_value(http_code
);
1623 web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value
);
1626 void PrintPreviewHandler::FillPrinterDescription(
1627 const std::string
& name
,
1628 const local_discovery::DeviceDescription
& description
,
1629 bool has_local_printing
,
1630 base::DictionaryValue
* printer_value
) {
1631 base::CommandLine
* command_line
= base::CommandLine::ForCurrentProcess();
1633 printer_value
->SetString("serviceName", name
);
1634 printer_value
->SetString("name", description
.name
);
1635 printer_value
->SetBoolean("hasLocalPrinting", has_local_printing
);
1636 printer_value
->SetBoolean(
1638 description
.id
.empty() &&
1639 command_line
->HasSwitch(switches::kEnablePrintPreviewRegisterPromos
));
1640 printer_value
->SetString("cloudID", description
.id
);
1643 #endif // defined(ENABLE_SERVICE_DISCOVERY)
1645 void PrintPreviewHandler::EnsureExtensionPrinterHandlerSet() {
1646 if (extension_printer_handler_
.get())
1649 extension_printer_handler_
=
1650 PrinterHandler::CreateForExtensionPrinters(Profile::FromWebUI(web_ui()));
1653 void PrintPreviewHandler::OnGotPrintersForExtension(
1654 const base::ListValue
& printers
,
1656 web_ui()->CallJavascriptFunction("onExtensionPrintersAdded", printers
,
1657 base::FundamentalValue(done
));
1660 void PrintPreviewHandler::OnGotExtensionPrinterCapabilities(
1661 const std::string
& printer_id
,
1662 const base::DictionaryValue
& capabilities
) {
1663 if (capabilities
.empty()) {
1664 web_ui()->CallJavascriptFunction("failedToGetExtensionPrinterCapabilities",
1665 base::StringValue(printer_id
));
1669 web_ui()->CallJavascriptFunction("onExtensionCapabilitiesSet",
1670 base::StringValue(printer_id
), capabilities
);
1673 void PrintPreviewHandler::OnExtensionPrintResult(bool success
,
1674 const std::string
& status
) {
1676 ClosePreviewDialog();
1680 // TODO(tbarzic): This function works for extension printers case too, but it
1681 // should be renamed to something more generic.
1682 web_ui()->CallJavascriptFunction("onPrivetPrintFailed",
1683 base::StringValue(status
));
1686 void PrintPreviewHandler::RegisterForMergeSession() {
1687 DCHECK(!reconcilor_
);
1688 Profile
* profile
= Profile::FromWebUI(web_ui());
1689 if (switches::IsEnableAccountConsistency() && !profile
->IsOffTheRecord()) {
1690 reconcilor_
= AccountReconcilorFactory::GetForProfile(profile
);
1692 reconcilor_
->AddMergeSessionObserver(this);
1696 void PrintPreviewHandler::UnregisterForMergeSession() {
1698 reconcilor_
->RemoveMergeSessionObserver(this);
1701 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1702 const base::Closure
& closure
) {
1703 pdf_file_saved_closure_
= closure
;