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