Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / print_preview / print_preview_handler.cc
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.
4
5 #include "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
6
7 #include <ctype.h>
8
9 #include <map>
10 #include <string>
11
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/sticky_settings.h"
49 #include "chrome/common/chrome_paths.h"
50 #include "chrome/common/chrome_switches.h"
51 #include "chrome/common/cloud_print/cloud_print_cdd_conversion.h"
52 #include "chrome/common/cloud_print/cloud_print_constants.h"
53 #include "chrome/common/crash_keys.h"
54 #include "chrome/common/pref_names.h"
55 #include "chrome/common/print_messages.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/signin/core/browser/account_reconcilor.h"
60 #include "components/signin/core/browser/profile_oauth2_token_service.h"
61 #include "components/signin/core/browser/signin_manager.h"
62 #include "components/signin/core/common/profile_management_switches.h"
63 #include "content/public/browser/browser_context.h"
64 #include "content/public/browser/browser_thread.h"
65 #include "content/public/browser/navigation_controller.h"
66 #include "content/public/browser/navigation_entry.h"
67 #include "content/public/browser/render_process_host.h"
68 #include "content/public/browser/render_view_host.h"
69 #include "content/public/browser/web_contents.h"
70 #include "content/public/browser/web_ui.h"
71 #include "google_apis/gaia/oauth2_token_service.h"
72 #include "printing/backend/print_backend.h"
73 #include "printing/backend/print_backend_consts.h"
74 #include "printing/metafile.h"
75 #include "printing/pdf_metafile_skia.h"
76 #include "printing/pdf_render_settings.h"
77 #include "printing/print_settings.h"
78 #include "printing/printing_context.h"
79 #include "printing/units.h"
80 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
81
82 #if defined(OS_CHROMEOS)
83 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
84 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
85 #endif
86
87 #if defined(ENABLE_SERVICE_DISCOVERY)
88 #include "chrome/browser/local_discovery/privet_constants.h"
89 #endif
90
91 using content::BrowserThread;
92 using content::RenderViewHost;
93 using content::WebContents;
94
95 namespace {
96
97 enum UserActionBuckets {
98   PRINT_TO_PRINTER,
99   PRINT_TO_PDF,
100   CANCEL,
101   FALLBACK_TO_ADVANCED_SETTINGS_DIALOG,
102   PREVIEW_FAILED,
103   PREVIEW_STARTED,
104   INITIATOR_CRASHED,  // UNUSED
105   INITIATOR_CLOSED,
106   PRINT_WITH_CLOUD_PRINT,
107   PRINT_WITH_PRIVET,
108   USERACTION_BUCKET_BOUNDARY
109 };
110
111 enum PrintSettingsBuckets {
112   LANDSCAPE = 0,
113   PORTRAIT,
114   COLOR,
115   BLACK_AND_WHITE,
116   COLLATE,
117   SIMPLEX,
118   DUPLEX,
119   TOTAL,
120   HEADERS_AND_FOOTERS,
121   CSS_BACKGROUND,
122   SELECTION_ONLY,
123   EXTERNAL_PDF_PREVIEW,
124   PAGE_RANGE,
125   DEFAULT_MEDIA,
126   NON_DEFAULT_MEDIA,
127   COPIES,
128   NON_DEFAULT_MARGINS,
129   PRINT_SETTINGS_BUCKET_BOUNDARY
130 };
131
132 void ReportUserActionHistogram(enum UserActionBuckets event) {
133   UMA_HISTOGRAM_ENUMERATION("PrintPreview.UserAction", event,
134                             USERACTION_BUCKET_BOUNDARY);
135 }
136
137 void ReportPrintSettingHistogram(enum PrintSettingsBuckets setting) {
138   UMA_HISTOGRAM_ENUMERATION("PrintPreview.PrintSettings", setting,
139                             PRINT_SETTINGS_BUCKET_BOUNDARY);
140 }
141
142 // Name of a dictionary field holding cloud print related data;
143 const char kAppState[] = "appState";
144 // Name of a dictionary field holding the initiator title.
145 const char kInitiatorTitle[] = "initiatorTitle";
146 // Name of a dictionary field holding the measurement system according to the
147 // locale.
148 const char kMeasurementSystem[] = "measurementSystem";
149 // Name of a dictionary field holding the number format according to the locale.
150 const char kNumberFormat[] = "numberFormat";
151 // Name of a dictionary field specifying whether to print automatically in
152 // kiosk mode. See http://crbug.com/31395.
153 const char kPrintAutomaticallyInKioskMode[] = "printAutomaticallyInKioskMode";
154 // Dictionary field to indicate whether Chrome is running in forced app (app
155 // kiosk) mode. It's not the same as desktop Chrome kiosk (the one above).
156 const char kAppKioskMode[] = "appKioskMode";
157 // Dictionary field to store Cloud Print base URL.
158 const char kCloudPrintUrl[] = "cloudPrintUrl";
159 #if defined(OS_WIN)
160 const char kHidePrintWithSystemDialogLink[] = "hidePrintWithSystemDialogLink";
161 #endif
162 // Name of a dictionary field holding the state of selection for document.
163 const char kDocumentHasSelection[] = "documentHasSelection";
164
165 // Id of the predefined PDF printer.
166 const char kLocalPdfPrinterId[] = "Save as PDF";
167
168 // Additional printer capability setting keys.
169 const char kPrinterId[] = "printerId";
170 const char kPrinterCapabilities[] = "capabilities";
171
172 // Get the print job settings dictionary from |args|. The caller takes
173 // ownership of the returned DictionaryValue. Returns NULL on failure.
174 base::DictionaryValue* GetSettingsDictionary(const base::ListValue* args) {
175   std::string json_str;
176   if (!args->GetString(0, &json_str)) {
177     NOTREACHED() << "Could not read JSON argument";
178     return NULL;
179   }
180   if (json_str.empty()) {
181     NOTREACHED() << "Empty print job settings";
182     return NULL;
183   }
184   scoped_ptr<base::DictionaryValue> settings(
185       static_cast<base::DictionaryValue*>(
186           base::JSONReader::Read(json_str)));
187   if (!settings.get() || !settings->IsType(base::Value::TYPE_DICTIONARY)) {
188     NOTREACHED() << "Print job settings must be a dictionary.";
189     return NULL;
190   }
191
192   if (settings->empty()) {
193     NOTREACHED() << "Print job settings dictionary is empty";
194     return NULL;
195   }
196
197   return settings.release();
198 }
199
200 // Track the popularity of print settings and report the stats.
201 void ReportPrintSettingsStats(const base::DictionaryValue& settings) {
202   ReportPrintSettingHistogram(TOTAL);
203
204   const base::ListValue* page_range_array = NULL;
205   if (settings.GetList(printing::kSettingPageRange, &page_range_array) &&
206       !page_range_array->empty()) {
207     ReportPrintSettingHistogram(PAGE_RANGE);
208   }
209
210   const base::DictionaryValue* media_size_value = NULL;
211   if (settings.GetDictionary(printing::kSettingMediaSize, &media_size_value) &&
212       !media_size_value->empty()) {
213     bool is_default = false;
214     if (media_size_value->GetBoolean(printing::kSettingMediaSizeIsDefault,
215                                      &is_default) &&
216         is_default) {
217       ReportPrintSettingHistogram(DEFAULT_MEDIA);
218     } else {
219       ReportPrintSettingHistogram(NON_DEFAULT_MEDIA);
220     }
221   }
222
223   bool landscape = false;
224   if (settings.GetBoolean(printing::kSettingLandscape, &landscape))
225     ReportPrintSettingHistogram(landscape ? LANDSCAPE : PORTRAIT);
226
227   int copies = 1;
228   if (settings.GetInteger(printing::kSettingCopies, &copies) && copies > 1)
229     ReportPrintSettingHistogram(COPIES);
230
231   bool collate = false;
232   if (settings.GetBoolean(printing::kSettingCollate, &collate) && collate)
233     ReportPrintSettingHistogram(COLLATE);
234
235   int duplex_mode = 0;
236   if (settings.GetInteger(printing::kSettingDuplexMode, &duplex_mode))
237     ReportPrintSettingHistogram(duplex_mode ? DUPLEX : SIMPLEX);
238
239   int color_mode = 0;
240   if (settings.GetInteger(printing::kSettingColor, &color_mode)) {
241     ReportPrintSettingHistogram(
242         printing::IsColorModelSelected(color_mode) ? COLOR : BLACK_AND_WHITE);
243   }
244
245   int margins_type = 0;
246   if (settings.GetInteger(printing::kSettingMarginsType, &margins_type) &&
247       margins_type != 0) {
248     ReportPrintSettingHistogram(NON_DEFAULT_MARGINS);
249   }
250
251   bool headers = false;
252   if (settings.GetBoolean(printing::kSettingHeaderFooterEnabled, &headers) &&
253       headers) {
254     ReportPrintSettingHistogram(HEADERS_AND_FOOTERS);
255   }
256
257   bool css_background = false;
258   if (settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
259                           &css_background) && css_background) {
260     ReportPrintSettingHistogram(CSS_BACKGROUND);
261   }
262
263   bool selection_only = false;
264   if (settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
265                           &selection_only) && selection_only) {
266     ReportPrintSettingHistogram(SELECTION_ONLY);
267   }
268
269   bool external_preview = false;
270   if (settings.GetBoolean(printing::kSettingOpenPDFInPreview,
271                           &external_preview) && external_preview) {
272     ReportPrintSettingHistogram(EXTERNAL_PDF_PREVIEW);
273   }
274 }
275
276 // Callback that stores a PDF file on disk.
277 void PrintToPdfCallback(const scoped_refptr<base::RefCountedBytes>& data,
278                         const base::FilePath& path,
279                         const base::Closure& pdf_file_saved_closure) {
280   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
281   printing::PdfMetafileSkia metafile;
282   metafile.InitFromData(static_cast<const void*>(data->front()), data->size());
283   base::File file(path,
284                   base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
285   metafile.SaveTo(&file);
286   if (!pdf_file_saved_closure.is_null())
287     pdf_file_saved_closure.Run();
288 }
289
290 std::string GetDefaultPrinterOnFileThread() {
291   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
292
293   scoped_refptr<printing::PrintBackend> print_backend(
294       printing::PrintBackend::CreateInstance(NULL));
295
296   std::string default_printer = print_backend->GetDefaultPrinterName();
297   VLOG(1) << "Default Printer: " << default_printer;
298   return default_printer;
299 }
300
301 class PrintingContextDelegate : public printing::PrintingContext::Delegate {
302  public:
303   // PrintingContext::Delegate methods.
304   virtual gfx::NativeView GetParentView() OVERRIDE { return NULL; }
305   virtual std::string GetAppLocale() OVERRIDE {
306     return g_browser_process->GetApplicationLocale();
307   }
308 };
309
310 gfx::Size GetDefaultPdfMediaSizeMicrons() {
311   PrintingContextDelegate delegate;
312   scoped_ptr<printing::PrintingContext> printing_context(
313       printing::PrintingContext::Create(&delegate));
314   if (printing::PrintingContext::OK != printing_context->UsePdfSettings() ||
315       printing_context->settings().device_units_per_inch() <= 0) {
316     return gfx::Size();
317   }
318   gfx::Size pdf_media_size = printing_context->GetPdfPaperSizeDeviceUnits();
319   float deviceMicronsPerDeviceUnit =
320       (printing::kHundrethsMMPerInch * 10.0f) /
321       printing_context->settings().device_units_per_inch();
322   return gfx::Size(pdf_media_size.width() * deviceMicronsPerDeviceUnit,
323                    pdf_media_size.height() * deviceMicronsPerDeviceUnit);
324 }
325
326 typedef base::Callback<void(const base::DictionaryValue*)>
327     GetPdfCapabilitiesCallback;
328
329 scoped_ptr<base::DictionaryValue> GetPdfCapabilitiesOnFileThread(
330     const std::string& locale) {
331   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
332
333   cloud_devices::CloudDeviceDescription description;
334   using namespace cloud_devices::printer;
335
336   OrientationCapability orientation;
337   orientation.AddOption(cloud_devices::printer::PORTRAIT);
338   orientation.AddOption(cloud_devices::printer::LANDSCAPE);
339   orientation.AddDefaultOption(AUTO_ORIENTATION, true);
340   orientation.SaveTo(&description);
341
342   ColorCapability color;
343   {
344     Color standard_color(STANDARD_COLOR);
345     standard_color.vendor_id = base::IntToString(printing::COLOR);
346     color.AddDefaultOption(standard_color, true);
347   }
348   color.SaveTo(&description);
349
350   static const cloud_devices::printer::MediaType kPdfMedia[] = {
351     ISO_A4,
352     ISO_A3,
353     NA_LETTER,
354     NA_LEGAL,
355     NA_LEDGER
356   };
357   const gfx::Size default_media_size = GetDefaultPdfMediaSizeMicrons();
358   Media default_media(
359       "", "", default_media_size.width(), default_media_size.height());
360   if (!default_media.MatchBySize() ||
361       std::find(kPdfMedia,
362                 kPdfMedia + arraysize(kPdfMedia),
363                 default_media.type) == kPdfMedia + arraysize(kPdfMedia)) {
364     default_media = Media(locale == "en-US" ? NA_LETTER : ISO_A4);
365   }
366   MediaCapability media;
367   for (size_t i = 0; i < arraysize(kPdfMedia); ++i) {
368     Media media_option(kPdfMedia[i]);
369     media.AddDefaultOption(media_option,
370                            default_media.type == media_option.type);
371   }
372   media.SaveTo(&description);
373
374   return scoped_ptr<base::DictionaryValue>(description.root().DeepCopy());
375 }
376
377 scoped_ptr<base::DictionaryValue> GetLocalPrinterCapabilitiesOnFileThread(
378     const std::string& printer_name) {
379   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
380
381   scoped_refptr<printing::PrintBackend> print_backend(
382       printing::PrintBackend::CreateInstance(NULL));
383
384   VLOG(1) << "Get printer capabilities start for " << printer_name;
385   crash_keys::ScopedPrinterInfo crash_key(
386       print_backend->GetPrinterDriverInfo(printer_name));
387
388   if (!print_backend->IsValidPrinter(printer_name)) {
389     LOG(WARNING) << "Invalid printer " << printer_name;
390     return scoped_ptr<base::DictionaryValue>();
391   }
392
393   printing::PrinterSemanticCapsAndDefaults info;
394   if (!print_backend->GetPrinterSemanticCapsAndDefaults(printer_name, &info)) {
395     LOG(WARNING) << "Failed to get capabilities for " << printer_name;
396     return scoped_ptr<base::DictionaryValue>();
397   }
398
399   scoped_ptr<base::DictionaryValue> description(
400       cloud_print::PrinterSemanticCapsAndDefaultsToCdd(info));
401   if (!description) {
402     LOG(WARNING) << "Failed to convert capabilities for " << printer_name;
403     return scoped_ptr<base::DictionaryValue>();
404   }
405
406   return description.Pass();
407 }
408
409 void EnumeratePrintersOnFileThread(base::ListValue* printers) {
410   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
411
412   scoped_refptr<printing::PrintBackend> print_backend(
413       printing::PrintBackend::CreateInstance(NULL));
414
415   VLOG(1) << "Enumerate printers start";
416   printing::PrinterList printer_list;
417   print_backend->EnumeratePrinters(&printer_list);
418
419   for (printing::PrinterList::iterator it = printer_list.begin();
420        it != printer_list.end(); ++it) {
421     base::DictionaryValue* printer_info = new base::DictionaryValue;
422     printers->Append(printer_info);
423     std::string printer_name;
424     std::string printer_description;
425 #if defined(OS_MACOSX)
426     // On Mac, |it->printer_description| specifies the printer name and
427     // |it->printer_name| specifies the device name / printer queue name.
428     printer_name = it->printer_description;
429     if (!it->options[kDriverNameTagName].empty())
430       printer_description = it->options[kDriverNameTagName];
431 #else
432     printer_name = it->printer_name;
433     printer_description = it->printer_description;
434 #endif
435     printer_info->SetString(printing::kSettingDeviceName, it->printer_name);
436     printer_info->SetString(printing::kSettingPrinterDescription,
437                             printer_description);
438     printer_info->SetString(printing::kSettingPrinterName, printer_name);
439     VLOG(1) << "Found printer " << printer_name
440             << " with device name " << it->printer_name;
441
442     base::DictionaryValue* options = new base::DictionaryValue;
443     printer_info->Set(printing::kSettingPrinterOptions, options);
444     for (std::map<std::string, std::string>::iterator opt = it->options.begin();
445          opt != it->options.end();
446          ++opt) {
447       options->SetString(opt->first, opt->second);
448     }
449
450     VLOG(1) << "Found printer " << printer_name << " with device name "
451             << it->printer_name;
452   }
453   VLOG(1) << "Enumerate printers finished, found " << printers->GetSize()
454           << " printers";
455 }
456
457 typedef base::Callback<void(const base::DictionaryValue*)>
458     GetPrinterCapabilitiesSuccessCallback;
459 typedef base::Callback<void(const std::string&)>
460     GetPrinterCapabilitiesFailureCallback;
461
462 void GetPrinterCapabilitiesOnFileThread(
463     const std::string& printer_name,
464     const std::string& locale,
465     const GetPrinterCapabilitiesSuccessCallback& success_cb,
466     const GetPrinterCapabilitiesFailureCallback& failure_cb) {
467   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
468   DCHECK(!printer_name.empty());
469
470   scoped_ptr<base::DictionaryValue> printer_capabilities(
471       printer_name == kLocalPdfPrinterId ?
472       GetPdfCapabilitiesOnFileThread(locale) :
473       GetLocalPrinterCapabilitiesOnFileThread(printer_name));
474   if (!printer_capabilities) {
475     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
476                             base::Bind(failure_cb, printer_name));
477     return;
478   }
479
480   scoped_ptr<base::DictionaryValue> printer_info(new base::DictionaryValue);
481   printer_info->SetString(kPrinterId, printer_name);
482   printer_info->Set(kPrinterCapabilities, printer_capabilities.release());
483
484   BrowserThread::PostTask(
485       BrowserThread::UI, FROM_HERE,
486       base::Bind(success_cb, base::Owned(printer_info.release())));
487 }
488
489 base::LazyInstance<printing::StickySettings> g_sticky_settings =
490     LAZY_INSTANCE_INITIALIZER;
491
492 printing::StickySettings* GetStickySettings() {
493   return g_sticky_settings.Pointer();
494 }
495
496 }  // namespace
497
498 class PrintPreviewHandler::AccessTokenService
499     : public OAuth2TokenService::Consumer {
500  public:
501   explicit AccessTokenService(PrintPreviewHandler* handler)
502       : OAuth2TokenService::Consumer("print_preview"),
503         handler_(handler) {
504   }
505
506   void RequestToken(const std::string& type) {
507     if (requests_.find(type) != requests_.end())
508       return;  // Already in progress.
509
510     OAuth2TokenService* service = NULL;
511     std::string account_id;
512     if (type == "profile") {
513       Profile* profile = Profile::FromWebUI(handler_->web_ui());
514       if (profile) {
515         ProfileOAuth2TokenService* token_service =
516             ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
517         SigninManagerBase* signin_manager =
518             SigninManagerFactory::GetInstance()->GetForProfile(profile);
519         account_id = signin_manager->GetAuthenticatedAccountId();
520         service = token_service;
521       }
522     } else if (type == "device") {
523 #if defined(OS_CHROMEOS)
524       chromeos::DeviceOAuth2TokenService* token_service =
525           chromeos::DeviceOAuth2TokenServiceFactory::Get();
526       account_id = token_service->GetRobotAccountId();
527       service = token_service;
528 #endif
529     }
530
531     if (service) {
532       OAuth2TokenService::ScopeSet oauth_scopes;
533       oauth_scopes.insert(cloud_devices::kCloudPrintAuthScope);
534       scoped_ptr<OAuth2TokenService::Request> request(
535           service->StartRequest(account_id, oauth_scopes, this));
536       requests_[type].reset(request.release());
537     } else {
538       handler_->SendAccessToken(type, std::string());  // Unknown type.
539     }
540   }
541
542   virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
543                                  const std::string& access_token,
544                                  const base::Time& expiration_time) OVERRIDE {
545     OnServiceResponce(request, access_token);
546   }
547
548   virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
549                                  const GoogleServiceAuthError& error) OVERRIDE {
550     OnServiceResponce(request, std::string());
551   }
552
553  private:
554   void OnServiceResponce(const OAuth2TokenService::Request* request,
555                          const std::string& access_token) {
556     for (Requests::iterator i = requests_.begin(); i != requests_.end(); ++i) {
557       if (i->second == request) {
558         handler_->SendAccessToken(i->first, access_token);
559         requests_.erase(i);
560         return;
561       }
562     }
563     NOTREACHED();
564   }
565
566   typedef std::map<std::string,
567                    linked_ptr<OAuth2TokenService::Request> > Requests;
568   Requests requests_;
569   PrintPreviewHandler* handler_;
570
571   DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
572 };
573
574 PrintPreviewHandler::PrintPreviewHandler()
575     : regenerate_preview_request_count_(0),
576       manage_printers_dialog_request_count_(0),
577       manage_cloud_printers_dialog_request_count_(0),
578       reported_failed_preview_(false),
579       has_logged_printers_count_(false),
580       reconcilor_(NULL),
581       weak_factory_(this) {
582   ReportUserActionHistogram(PREVIEW_STARTED);
583 }
584
585 PrintPreviewHandler::~PrintPreviewHandler() {
586   if (select_file_dialog_.get())
587     select_file_dialog_->ListenerDestroyed();
588
589   UnregisterForMergeSession();
590 }
591
592 void PrintPreviewHandler::RegisterMessages() {
593   web_ui()->RegisterMessageCallback("getPrinters",
594       base::Bind(&PrintPreviewHandler::HandleGetPrinters,
595                  base::Unretained(this)));
596   web_ui()->RegisterMessageCallback("getPreview",
597       base::Bind(&PrintPreviewHandler::HandleGetPreview,
598                  base::Unretained(this)));
599   web_ui()->RegisterMessageCallback("print",
600       base::Bind(&PrintPreviewHandler::HandlePrint,
601                  base::Unretained(this)));
602   web_ui()->RegisterMessageCallback("getPrinterCapabilities",
603       base::Bind(&PrintPreviewHandler::HandleGetPrinterCapabilities,
604                  base::Unretained(this)));
605 #if !defined(DISABLE_BASIC_PRINTING)
606   web_ui()->RegisterMessageCallback("showSystemDialog",
607       base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
608                  base::Unretained(this)));
609 #endif  // !DISABLE_BASIC_PRINTING
610   web_ui()->RegisterMessageCallback("signIn",
611       base::Bind(&PrintPreviewHandler::HandleSignin,
612                  base::Unretained(this)));
613   web_ui()->RegisterMessageCallback("getAccessToken",
614       base::Bind(&PrintPreviewHandler::HandleGetAccessToken,
615                  base::Unretained(this)));
616   web_ui()->RegisterMessageCallback("manageCloudPrinters",
617       base::Bind(&PrintPreviewHandler::HandleManageCloudPrint,
618                  base::Unretained(this)));
619   web_ui()->RegisterMessageCallback("manageLocalPrinters",
620       base::Bind(&PrintPreviewHandler::HandleManagePrinters,
621                  base::Unretained(this)));
622   web_ui()->RegisterMessageCallback("closePrintPreviewDialog",
623       base::Bind(&PrintPreviewHandler::HandleClosePreviewDialog,
624                  base::Unretained(this)));
625   web_ui()->RegisterMessageCallback("hidePreview",
626       base::Bind(&PrintPreviewHandler::HandleHidePreview,
627                  base::Unretained(this)));
628   web_ui()->RegisterMessageCallback("cancelPendingPrintRequest",
629       base::Bind(&PrintPreviewHandler::HandleCancelPendingPrintRequest,
630                  base::Unretained(this)));
631   web_ui()->RegisterMessageCallback("saveAppState",
632       base::Bind(&PrintPreviewHandler::HandleSaveAppState,
633                  base::Unretained(this)));
634   web_ui()->RegisterMessageCallback("getInitialSettings",
635       base::Bind(&PrintPreviewHandler::HandleGetInitialSettings,
636                  base::Unretained(this)));
637   web_ui()->RegisterMessageCallback("printWithCloudPrintDialog",
638       base::Bind(&PrintPreviewHandler::HandlePrintWithCloudPrintDialog,
639                  base::Unretained(this)));
640   web_ui()->RegisterMessageCallback("forceOpenNewTab",
641       base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
642                  base::Unretained(this)));
643   web_ui()->RegisterMessageCallback("getPrivetPrinters",
644       base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
645                  base::Unretained(this)));
646   web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
647       base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
648                  base::Unretained(this)));
649   web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
650       base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
651                  base::Unretained(this)));
652   RegisterForMergeSession();
653 }
654
655 bool PrintPreviewHandler::PrivetPrintingEnabled() {
656 #if defined(ENABLE_SERVICE_DISCOVERY)
657   return true;
658 #else
659   return false;
660 #endif
661 }
662
663 WebContents* PrintPreviewHandler::preview_web_contents() const {
664   return web_ui()->GetWebContents();
665 }
666
667 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
668   base::ListValue* results = new base::ListValue;
669   BrowserThread::PostTaskAndReply(
670       BrowserThread::FILE, FROM_HERE,
671       base::Bind(&EnumeratePrintersOnFileThread,
672                  base::Unretained(results)),
673       base::Bind(&PrintPreviewHandler::SetupPrinterList,
674                  weak_factory_.GetWeakPtr(),
675                  base::Owned(results)));
676 }
677
678 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
679   if (!PrivetPrintingEnabled())
680     return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
681 #if defined(ENABLE_SERVICE_DISCOVERY)
682   local_discovery::ServiceDiscoverySharedClient::GetInstanceWithoutAlert(
683       base::Bind(&PrintPreviewHandler::StartPrivetLister,
684                  weak_factory_.GetWeakPtr()));
685 #endif  // ENABLE_SERVICE_DISCOVERY
686 }
687
688 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
689     const base::ListValue* args) {
690 #if defined(ENABLE_SERVICE_DISCOVERY)
691   if (PrivetPrintingEnabled() && printer_lister_) {
692     printer_lister_->Stop();
693   }
694 #endif
695 }
696
697 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
698     const base::ListValue* args) {
699 #if defined(ENABLE_SERVICE_DISCOVERY)
700   std::string name;
701   bool success = args->GetString(0, &name);
702   DCHECK(success);
703
704   CreatePrivetHTTP(
705       name,
706       base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
707                  base::Unretained(this)));
708 #endif
709 }
710
711 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
712   DCHECK_EQ(3U, args->GetSize());
713   scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
714   if (!settings.get())
715     return;
716   int request_id = -1;
717   if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
718     return;
719
720   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
721       web_ui()->GetController());
722   print_preview_ui->OnPrintPreviewRequest(request_id);
723   // Add an additional key in order to identify |print_preview_ui| later on
724   // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
725   // thread.
726   settings->SetInteger(printing::kPreviewUIID,
727                        print_preview_ui->GetIDForPrintPreviewUI());
728
729   // Increment request count.
730   ++regenerate_preview_request_count_;
731
732   WebContents* initiator = GetInitiator();
733   if (!initiator) {
734     ReportUserActionHistogram(INITIATOR_CLOSED);
735     print_preview_ui->OnClosePrintPreviewDialog();
736     return;
737   }
738
739   // Retrieve the page title and url and send it to the renderer process if
740   // headers and footers are to be displayed.
741   bool display_header_footer = false;
742   if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
743                             &display_header_footer)) {
744     NOTREACHED();
745   }
746   if (display_header_footer) {
747     settings->SetString(printing::kSettingHeaderFooterTitle,
748                         initiator->GetTitle());
749     std::string url;
750     content::NavigationEntry* entry =
751         initiator->GetController().GetLastCommittedEntry();
752     if (entry)
753       url = entry->GetVirtualURL().spec();
754     settings->SetString(printing::kSettingHeaderFooterURL, url);
755   }
756
757   bool generate_draft_data = false;
758   bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
759                                       &generate_draft_data);
760   DCHECK(success);
761
762   if (!generate_draft_data) {
763     double draft_page_count_double = -1;
764     success = args->GetDouble(1, &draft_page_count_double);
765     DCHECK(success);
766     int draft_page_count = static_cast<int>(draft_page_count_double);
767
768     bool preview_modifiable = false;
769     success = args->GetBoolean(2, &preview_modifiable);
770     DCHECK(success);
771
772     if (draft_page_count != -1 && preview_modifiable &&
773         print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
774       settings->SetBoolean(printing::kSettingGenerateDraftData, true);
775     }
776   }
777
778   VLOG(1) << "Print preview request start";
779   RenderViewHost* rvh = initiator->GetRenderViewHost();
780   rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
781 }
782
783 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
784   ReportStats();
785
786   // Record the number of times the user requests to regenerate preview data
787   // before printing.
788   UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
789                        regenerate_preview_request_count_);
790
791   scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
792   if (!settings.get())
793     return;
794
795   ReportPrintSettingsStats(*settings);
796
797   // Never try to add headers/footers here. It's already in the generated PDF.
798   settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
799
800   bool print_to_pdf = false;
801   bool is_cloud_printer = false;
802   bool print_with_privet = false;
803
804   bool open_pdf_in_preview = false;
805 #if defined(OS_MACOSX)
806   open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
807 #endif
808
809   if (!open_pdf_in_preview) {
810     settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
811     settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
812     is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
813   }
814
815   int page_count = 0;
816   settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
817
818   if (print_to_pdf) {
819     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
820     ReportUserActionHistogram(PRINT_TO_PDF);
821     PrintToPdf();
822     return;
823   }
824
825 #if defined(ENABLE_SERVICE_DISCOVERY)
826   if (print_with_privet && PrivetPrintingEnabled()) {
827     std::string printer_name;
828     std::string print_ticket;
829     std::string capabilities;
830     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
831     ReportUserActionHistogram(PRINT_WITH_PRIVET);
832
833     int width = 0;
834     int height = 0;
835     if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
836         !settings->GetString(printing::kSettingTicket, &print_ticket) ||
837         !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
838         !settings->GetInteger(printing::kSettingPageWidth, &width) ||
839         !settings->GetInteger(printing::kSettingPageHeight, &height) ||
840         width <= 0 || height <= 0) {
841       NOTREACHED();
842       base::FundamentalValue http_code_value(-1);
843       web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
844       return;
845     }
846
847     PrintToPrivetPrinter(
848         printer_name, print_ticket, capabilities, gfx::Size(width, height));
849     return;
850   }
851 #endif
852
853   scoped_refptr<base::RefCountedBytes> data;
854   base::string16 title;
855   if (!GetPreviewDataAndTitle(&data, &title)) {
856     // Nothing to print, no preview available.
857     return;
858   }
859
860   if (is_cloud_printer) {
861     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
862                          page_count);
863     ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
864     SendCloudPrintJob(data.get());
865   } else {
866     bool system_dialog = false;
867     settings->GetBoolean(printing::kSettingShowSystemDialog, &system_dialog);
868     if (system_dialog) {
869       UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count);
870       ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
871     } else {
872       UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
873       ReportUserActionHistogram(PRINT_TO_PRINTER);
874     }
875
876     // This tries to activate the initiator as well, so do not clear the
877     // association with the initiator yet.
878     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
879         web_ui()->GetController());
880     print_preview_ui->OnHidePreviewDialog();
881
882     // Do this so the initiator can open a new print preview dialog, while the
883     // current print preview dialog is still handling its print job.
884     WebContents* initiator = GetInitiator();
885     if (initiator) {
886       // Save initiator IDs. |PrintingMessageFilter::OnUpdatePrintSettings|
887       // would be called when initiator info is cleared.
888       settings->SetInteger(printing::kPreviewInitiatorHostId,
889                            initiator->GetRenderProcessHost()->GetID());
890       settings->SetInteger(printing::kPreviewInitiatorRoutingId,
891                            initiator->GetRoutingID());
892     }
893
894     ClearInitiatorDetails();
895
896     // The PDF being printed contains only the pages that the user selected,
897     // so ignore the page range and print all pages.
898     settings->Remove(printing::kSettingPageRange, NULL);
899     // Reset selection only flag for the same reason.
900     settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
901
902     // Set ID to know whether printing is for preview.
903     settings->SetInteger(printing::kPreviewUIID,
904                          print_preview_ui->GetIDForPrintPreviewUI());
905     RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
906     rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
907                                                 *settings));
908
909     // For all other cases above, the preview dialog will stay open until the
910     // printing has finished. Then the dialog closes and PrintPreviewDone() gets
911     // called. In the case below, since the preview dialog will be hidden and
912     // not closed, we need to make this call.
913     if (initiator) {
914       printing::PrintViewManager* print_view_manager =
915           printing::PrintViewManager::FromWebContents(initiator);
916       print_view_manager->PrintPreviewDone();
917     }
918   }
919 }
920
921 void PrintPreviewHandler::PrintToPdf() {
922   if (!print_to_pdf_path_.empty()) {
923     // User has already selected a path, no need to show the dialog again.
924     PostPrintToPdfTask();
925   } else if (!select_file_dialog_.get() ||
926              !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
927                  preview_web_contents()->GetNativeView()))) {
928     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
929         web_ui()->GetController());
930     // Pre-populating select file dialog with print job title.
931     base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
932
933 #if defined(OS_WIN)
934     base::FilePath::StringType print_job_title(print_job_title_utf16);
935 #elif defined(OS_POSIX)
936     base::FilePath::StringType print_job_title =
937         base::UTF16ToUTF8(print_job_title_utf16);
938 #endif
939
940     base::i18n::ReplaceIllegalCharactersInPath(&print_job_title, '_');
941     base::FilePath default_filename(print_job_title);
942     default_filename =
943         default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
944
945     SelectFile(default_filename);
946   }
947 }
948
949 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
950   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
951       web_ui()->GetController());
952   print_preview_ui->OnHidePreviewDialog();
953 }
954
955 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
956     const base::ListValue* /*args*/) {
957   WebContents* initiator = GetInitiator();
958   if (initiator)
959     ClearInitiatorDetails();
960   chrome::ShowPrintErrorDialog();
961 }
962
963 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
964   std::string data_to_save;
965   printing::StickySettings* sticky_settings = GetStickySettings();
966   if (args->GetString(0, &data_to_save) && !data_to_save.empty())
967     sticky_settings->StoreAppState(data_to_save);
968   sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
969       preview_web_contents()->GetBrowserContext())->GetPrefs());
970 }
971
972 void PrintPreviewHandler::HandleGetPrinterCapabilities(
973     const base::ListValue* args) {
974   std::string printer_name;
975   bool ret = args->GetString(0, &printer_name);
976   if (!ret || printer_name.empty())
977     return;
978
979   GetPrinterCapabilitiesSuccessCallback success_cb =
980       base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
981                  weak_factory_.GetWeakPtr());
982   GetPrinterCapabilitiesFailureCallback failure_cb =
983       base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
984                  weak_factory_.GetWeakPtr());
985   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
986                           base::Bind(&GetPrinterCapabilitiesOnFileThread,
987                                      printer_name,
988                                      g_browser_process->GetApplicationLocale(),
989                                      success_cb, failure_cb));
990 }
991
992 void PrintPreviewHandler::OnSigninComplete() {
993   PrintPreviewUI* print_preview_ui =
994       static_cast<PrintPreviewUI*>(web_ui()->GetController());
995   if (print_preview_ui)
996     print_preview_ui->OnReloadPrintersList();
997 }
998
999 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
1000   bool add_account = false;
1001   bool success = args->GetBoolean(0, &add_account);
1002   DCHECK(success);
1003
1004   Profile* profile = Profile::FromBrowserContext(
1005       preview_web_contents()->GetBrowserContext());
1006   chrome::ScopedTabbedBrowserDisplayer displayer(
1007       profile, chrome::GetActiveDesktop());
1008   print_dialog_cloud::CreateCloudPrintSigninTab(
1009       displayer.browser(),
1010       add_account,
1011       base::Bind(&PrintPreviewHandler::OnSigninComplete,
1012                  weak_factory_.GetWeakPtr()));
1013 }
1014
1015 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
1016   std::string type;
1017   if (!args->GetString(0, &type))
1018     return;
1019   if (!token_service_)
1020     token_service_.reset(new AccessTokenService(this));
1021   token_service_->RequestToken(type);
1022 }
1023
1024 void PrintPreviewHandler::PrintWithCloudPrintDialog() {
1025   // Record the number of times the user asks to print via cloud print
1026   // instead of the print preview dialog.
1027   ReportStats();
1028
1029   scoped_refptr<base::RefCountedBytes> data;
1030   base::string16 title;
1031   if (!GetPreviewDataAndTitle(&data, &title)) {
1032     // Nothing to print, no preview available.
1033     return;
1034   }
1035
1036   gfx::NativeWindow modal_parent = platform_util::GetTopLevel(
1037       preview_web_contents()->GetNativeView());
1038   print_dialog_cloud::CreatePrintDialogForBytes(
1039       preview_web_contents()->GetBrowserContext(),
1040       modal_parent,
1041       data.get(),
1042       title,
1043       base::string16(),
1044       std::string("application/pdf"));
1045
1046   // Once the cloud print dialog comes up we're no longer in a background
1047   // printing situation.  Close the print preview.
1048   // TODO(abodenha@chromium.org) The flow should be changed as described in
1049   // http://code.google.com/p/chromium/issues/detail?id=44093
1050   ClosePreviewDialog();
1051 }
1052
1053 void PrintPreviewHandler::HandleManageCloudPrint(
1054     const base::ListValue* /*args*/) {
1055   ++manage_cloud_printers_dialog_request_count_;
1056   preview_web_contents()->OpenURL(content::OpenURLParams(
1057       cloud_devices::GetCloudPrintRelativeURL("manage.html"),
1058       content::Referrer(),
1059       NEW_FOREGROUND_TAB,
1060       ui::PAGE_TRANSITION_LINK,
1061       false));
1062 }
1063
1064 #if !defined(DISABLE_BASIC_PRINTING)
1065 void PrintPreviewHandler::HandleShowSystemDialog(
1066     const base::ListValue* /*args*/) {
1067   ReportStats();
1068   ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1069
1070   WebContents* initiator = GetInitiator();
1071   if (!initiator)
1072     return;
1073
1074   printing::PrintViewManager* print_view_manager =
1075       printing::PrintViewManager::FromWebContents(initiator);
1076   print_view_manager->set_observer(this);
1077   print_view_manager->PrintForSystemDialogNow();
1078
1079   // Cancel the pending preview request if exists.
1080   PrintPreviewUI* print_preview_ui =
1081       static_cast<PrintPreviewUI*>(web_ui()->GetController());
1082   print_preview_ui->OnCancelPendingPreviewRequest();
1083 }
1084 #endif  // !DISABLE_BASIC_PRINTING
1085
1086 void PrintPreviewHandler::HandleManagePrinters(
1087     const base::ListValue* /*args*/) {
1088   ++manage_printers_dialog_request_count_;
1089   printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1090 }
1091
1092 void PrintPreviewHandler::HandlePrintWithCloudPrintDialog(
1093     const base::ListValue* args) {
1094   int page_count = 0;
1095   if (!args || !args->GetInteger(0, &page_count))
1096     return;
1097   UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrintWebDialog",
1098                        page_count);
1099
1100   PrintWithCloudPrintDialog();
1101 }
1102
1103 void PrintPreviewHandler::HandleClosePreviewDialog(
1104     const base::ListValue* /*args*/) {
1105   ReportStats();
1106   ReportUserActionHistogram(CANCEL);
1107
1108   // Record the number of times the user requests to regenerate preview data
1109   // before cancelling.
1110   UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1111                        regenerate_preview_request_count_);
1112 }
1113
1114 void PrintPreviewHandler::ReportStats() {
1115   UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1116                        manage_printers_dialog_request_count_);
1117   UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1118                        manage_cloud_printers_dialog_request_count_);
1119 }
1120
1121 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1122     base::DictionaryValue* settings) {
1123
1124   // Getting the measurement system based on the locale.
1125   UErrorCode errorCode = U_ZERO_ERROR;
1126   const char* locale = g_browser_process->GetApplicationLocale().c_str();
1127   UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1128   if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1129     system = UMS_SI;
1130
1131   // Getting the number formatting based on the locale and writing to
1132   // dictionary.
1133   settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1134   settings->SetInteger(kMeasurementSystem, system);
1135 }
1136
1137 void PrintPreviewHandler::HandleGetInitialSettings(
1138     const base::ListValue* /*args*/) {
1139   // Send before SendInitialSettings to allow cloud printer auto select.
1140   SendCloudPrintEnabled();
1141   BrowserThread::PostTaskAndReplyWithResult(
1142       BrowserThread::FILE, FROM_HERE,
1143       base::Bind(&GetDefaultPrinterOnFileThread),
1144       base::Bind(&PrintPreviewHandler::SendInitialSettings,
1145                  weak_factory_.GetWeakPtr()));
1146 }
1147
1148 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1149   std::string url;
1150   if (!args->GetString(0, &url))
1151     return;
1152   Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1153   if (!browser)
1154     return;
1155   chrome::AddSelectedTabWithURL(browser,
1156                                 GURL(url),
1157                                 ui::PAGE_TRANSITION_LINK);
1158 }
1159
1160 void PrintPreviewHandler::SendInitialSettings(
1161     const std::string& default_printer) {
1162   PrintPreviewUI* print_preview_ui =
1163       static_cast<PrintPreviewUI*>(web_ui()->GetController());
1164
1165   base::DictionaryValue initial_settings;
1166   initial_settings.SetString(kInitiatorTitle,
1167                              print_preview_ui->initiator_title());
1168   initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1169                               print_preview_ui->source_is_modifiable());
1170   initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1171   initial_settings.SetBoolean(kDocumentHasSelection,
1172                               print_preview_ui->source_has_selection());
1173   initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1174                               print_preview_ui->print_selection_only());
1175   printing::StickySettings* sticky_settings = GetStickySettings();
1176   sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1177       preview_web_contents()->GetBrowserContext())->GetPrefs());
1178   if (sticky_settings->printer_app_state()) {
1179     initial_settings.SetString(kAppState,
1180                                *sticky_settings->printer_app_state());
1181   }
1182
1183   base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1184   initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1185                               cmdline->HasSwitch(switches::kKioskModePrinting));
1186   initial_settings.SetBoolean(kAppKioskMode,
1187                               chrome::IsRunningInForcedAppMode());
1188 #if defined(OS_WIN)
1189   // In Win8 metro, the system print dialog can only open on the desktop.  Doing
1190   // so will cause the browser to appear hung, so we don't show the link in
1191   // metro.
1192   bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1193   initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1194 #endif
1195
1196   if (print_preview_ui->source_is_modifiable())
1197     GetNumberFormatAndMeasurementSystem(&initial_settings);
1198   web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1199 }
1200
1201 void PrintPreviewHandler::ClosePreviewDialog() {
1202   PrintPreviewUI* print_preview_ui =
1203       static_cast<PrintPreviewUI*>(web_ui()->GetController());
1204   print_preview_ui->OnClosePrintPreviewDialog();
1205 }
1206
1207 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1208                                           const std::string& access_token) {
1209   VLOG(1) << "Get getAccessToken finished";
1210   web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1211                                    base::StringValue(type),
1212                                    base::StringValue(access_token));
1213 }
1214
1215 void PrintPreviewHandler::SendPrinterCapabilities(
1216     const base::DictionaryValue* settings_info) {
1217   VLOG(1) << "Get printer capabilities finished";
1218   web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1219                                    *settings_info);
1220 }
1221
1222 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1223     const std::string& printer_name) {
1224   VLOG(1) << "Get printer capabilities failed";
1225   base::StringValue printer_name_value(printer_name);
1226   web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1227                                    printer_name_value);
1228 }
1229
1230 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1231   if (!has_logged_printers_count_) {
1232     UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1233     has_logged_printers_count_ = true;
1234   }
1235
1236   web_ui()->CallJavascriptFunction("setPrinters", *printers);
1237 }
1238
1239 void PrintPreviewHandler::SendCloudPrintEnabled() {
1240   Profile* profile = Profile::FromBrowserContext(
1241       preview_web_contents()->GetBrowserContext());
1242   PrefService* prefs = profile->GetPrefs();
1243   if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1244     base::DictionaryValue settings;
1245     settings.SetString(kCloudPrintUrl,
1246                        GURL(cloud_devices::GetCloudPrintURL()).spec());
1247     settings.SetBoolean(kAppKioskMode, chrome::IsRunningInForcedAppMode());
1248     web_ui()->CallJavascriptFunction("setUseCloudPrint", settings);
1249   }
1250 }
1251
1252 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1253   // BASE64 encode the job data.
1254   std::string raw_data(reinterpret_cast<const char*>(data->front()),
1255                        data->size());
1256   std::string base64_data;
1257   base::Base64Encode(raw_data, &base64_data);
1258   base::StringValue data_value(base64_data);
1259
1260   web_ui()->CallJavascriptFunction("printToCloud", data_value);
1261 }
1262
1263 WebContents* PrintPreviewHandler::GetInitiator() const {
1264   printing::PrintPreviewDialogController* dialog_controller =
1265       printing::PrintPreviewDialogController::GetInstance();
1266   if (!dialog_controller)
1267     return NULL;
1268   return dialog_controller->GetInitiator(preview_web_contents());
1269 }
1270
1271 void PrintPreviewHandler::OnPrintDialogShown() {
1272   ClosePreviewDialog();
1273 }
1274
1275 void PrintPreviewHandler::MergeSessionCompleted(
1276     const std::string& account_id,
1277     const GoogleServiceAuthError& error) {
1278   OnSigninComplete();
1279 }
1280
1281 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
1282   ui::SelectFileDialog::FileTypeInfo file_type_info;
1283   file_type_info.extensions.resize(1);
1284   file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1285
1286   // Initializing |save_path_| if it is not already initialized.
1287   printing::StickySettings* sticky_settings = GetStickySettings();
1288   if (!sticky_settings->save_path()) {
1289     // Allowing IO operation temporarily. It is ok to do so here because
1290     // the select file dialog performs IO anyway in order to display the
1291     // folders and also it is modal.
1292     base::ThreadRestrictions::ScopedAllowIO allow_io;
1293     base::FilePath file_path;
1294     PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1295     sticky_settings->StoreSavePath(file_path);
1296     sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1297         preview_web_contents()->GetBrowserContext())->GetPrefs());
1298   }
1299
1300   select_file_dialog_ = ui::SelectFileDialog::Create(
1301       this, new ChromeSelectFilePolicy(preview_web_contents())),
1302   select_file_dialog_->SelectFile(
1303       ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1304       base::string16(),
1305       sticky_settings->save_path()->Append(default_filename),
1306       &file_type_info,
1307       0,
1308       base::FilePath::StringType(),
1309       platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1310       NULL);
1311 }
1312
1313 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1314   WebContents* initiator = GetInitiator();
1315   if (!initiator)
1316     return;
1317
1318   printing::PrintViewManager* print_view_manager =
1319       printing::PrintViewManager::FromWebContents(initiator);
1320   print_view_manager->set_observer(NULL);
1321 }
1322
1323 void PrintPreviewHandler::OnPrintPreviewFailed() {
1324   if (reported_failed_preview_)
1325     return;
1326   reported_failed_preview_ = true;
1327   ReportUserActionHistogram(PREVIEW_FAILED);
1328 }
1329
1330 #if !defined(DISABLE_BASIC_PRINTING)
1331 void PrintPreviewHandler::ShowSystemDialog() {
1332   HandleShowSystemDialog(NULL);
1333 }
1334 #endif  // !DISABLE_BASIC_PRINTING
1335
1336 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1337                                        int index, void* params) {
1338   // Updating |save_path_| to the newly selected folder.
1339   printing::StickySettings* sticky_settings = GetStickySettings();
1340   sticky_settings->StoreSavePath(path.DirName());
1341   sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1342       preview_web_contents()->GetBrowserContext())->GetPrefs());
1343   web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1344   print_to_pdf_path_ = path;
1345   PostPrintToPdfTask();
1346 }
1347
1348 void PrintPreviewHandler::PostPrintToPdfTask() {
1349   scoped_refptr<base::RefCountedBytes> data;
1350   base::string16 title;
1351   if (!GetPreviewDataAndTitle(&data, &title)) {
1352     NOTREACHED() << "Preview data was checked before file dialog.";
1353     return;
1354   }
1355   BrowserThread::PostTask(BrowserThread::FILE,
1356                           FROM_HERE,
1357                           base::Bind(&PrintToPdfCallback,
1358                                      data,
1359                                      print_to_pdf_path_,
1360                                      pdf_file_saved_closure_));
1361   print_to_pdf_path_ = base::FilePath();
1362   ClosePreviewDialog();
1363 }
1364
1365 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1366   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1367       web_ui()->GetController());
1368   print_preview_ui->OnFileSelectionCancelled();
1369 }
1370
1371 void PrintPreviewHandler::ClearInitiatorDetails() {
1372   WebContents* initiator = GetInitiator();
1373   if (!initiator)
1374     return;
1375
1376   // We no longer require the initiator details. Remove those details associated
1377   // with the preview dialog to allow the initiator to create another preview
1378   // dialog.
1379   printing::PrintPreviewDialogController* dialog_controller =
1380       printing::PrintPreviewDialogController::GetInstance();
1381   if (dialog_controller)
1382     dialog_controller->EraseInitiatorInfo(preview_web_contents());
1383 }
1384
1385 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1386     scoped_refptr<base::RefCountedBytes>* data,
1387     base::string16* title) const {
1388   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1389       web_ui()->GetController());
1390   scoped_refptr<base::RefCountedBytes> tmp_data;
1391   print_preview_ui->GetPrintPreviewDataForIndex(
1392       printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1393
1394   if (!tmp_data.get()) {
1395     // Nothing to print, no preview available.
1396     return false;
1397   }
1398   DCHECK(tmp_data->size() && tmp_data->front());
1399
1400   *data = tmp_data;
1401   *title = print_preview_ui->initiator_title();
1402   return true;
1403 }
1404
1405 #if defined(ENABLE_SERVICE_DISCOVERY)
1406
1407 void PrintPreviewHandler::StartPrivetLister(const scoped_refptr<
1408     local_discovery::ServiceDiscoverySharedClient>& client) {
1409   if (!PrivetPrintingEnabled())
1410     return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1411
1412   Profile* profile = Profile::FromWebUI(web_ui());
1413   DCHECK(!service_discovery_client_.get() ||
1414          service_discovery_client_.get() == client.get());
1415   service_discovery_client_ = client;
1416   printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
1417       service_discovery_client_.get(), profile->GetRequestContext(), this));
1418   printer_lister_->Start();
1419 }
1420
1421 void PrintPreviewHandler::LocalPrinterChanged(
1422     bool added,
1423     const std::string& name,
1424     bool has_local_printing,
1425     const local_discovery::DeviceDescription& description) {
1426   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1427   if (has_local_printing ||
1428       command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) {
1429     base::DictionaryValue info;
1430     FillPrinterDescription(name, description, has_local_printing, &info);
1431     web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1432   }
1433 }
1434
1435 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1436 }
1437
1438 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1439 }
1440
1441 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1442     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1443   if (!PrivetUpdateClient(http_client.Pass()))
1444     return;
1445
1446   privet_capabilities_operation_ =
1447       privet_http_client_->CreateCapabilitiesOperation(
1448           base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1449                      base::Unretained(this)));
1450   privet_capabilities_operation_->Start();
1451 }
1452
1453 bool PrintPreviewHandler::PrivetUpdateClient(
1454     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1455   if (!http_client) {
1456     SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1457     privet_http_resolution_.reset();
1458     return false;
1459   }
1460
1461   privet_local_print_operation_.reset();
1462   privet_capabilities_operation_.reset();
1463   privet_http_client_ =
1464       local_discovery::PrivetV1HTTPClient::CreateDefault(http_client.Pass());
1465
1466   privet_http_resolution_.reset();
1467
1468   return true;
1469 }
1470
1471 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1472     std::string print_ticket,
1473     std::string capabilities,
1474     gfx::Size page_size,
1475     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1476   if (!PrivetUpdateClient(http_client.Pass()))
1477     return;
1478
1479   StartPrivetLocalPrint(print_ticket, capabilities, page_size);
1480 }
1481
1482 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string& print_ticket,
1483                                                 const std::string& capabilities,
1484                                                 const gfx::Size& page_size) {
1485   privet_local_print_operation_ =
1486       privet_http_client_->CreateLocalPrintOperation(this);
1487
1488   privet_local_print_operation_->SetTicket(print_ticket);
1489   privet_local_print_operation_->SetCapabilities(capabilities);
1490
1491   scoped_refptr<base::RefCountedBytes> data;
1492   base::string16 title;
1493
1494   if (!GetPreviewDataAndTitle(&data, &title)) {
1495     base::FundamentalValue http_code_value(-1);
1496     web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1497     return;
1498   }
1499
1500   privet_local_print_operation_->SetJobname(base::UTF16ToUTF8(title));
1501   privet_local_print_operation_->SetPageSize(page_size);
1502   privet_local_print_operation_->SetData(data.get());
1503
1504   Profile* profile = Profile::FromWebUI(web_ui());
1505   SigninManagerBase* signin_manager =
1506       SigninManagerFactory::GetForProfileIfExists(profile);
1507
1508   if (signin_manager) {
1509     privet_local_print_operation_->SetUsername(
1510         signin_manager->GetAuthenticatedUsername());
1511   }
1512
1513   privet_local_print_operation_->Start();
1514 }
1515
1516
1517 void PrintPreviewHandler::OnPrivetCapabilities(
1518     const base::DictionaryValue* capabilities) {
1519   std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1520
1521   if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError) ||
1522       !printer_lister_) {
1523     SendPrivetCapabilitiesError(name);
1524     return;
1525   }
1526
1527   base::DictionaryValue printer_info;
1528   const local_discovery::DeviceDescription* description =
1529       printer_lister_->GetDeviceDescription(name);
1530
1531   if (!description) {
1532     SendPrivetCapabilitiesError(name);
1533     return;
1534   }
1535
1536   FillPrinterDescription(name, *description, true, &printer_info);
1537
1538   web_ui()->CallJavascriptFunction(
1539       "onPrivetCapabilitiesSet",
1540       printer_info,
1541       *capabilities);
1542
1543   privet_capabilities_operation_.reset();
1544 }
1545
1546 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1547     const std::string& device_name) {
1548   base::StringValue name_value(device_name);
1549   web_ui()->CallJavascriptFunction(
1550       "failedToGetPrivetPrinterCapabilities",
1551       name_value);
1552 }
1553
1554 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string& device_name,
1555                                                const std::string& ticket,
1556                                                const std::string& capabilities,
1557                                                const gfx::Size& page_size) {
1558   CreatePrivetHTTP(
1559       device_name,
1560       base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1561                  base::Unretained(this),
1562                  ticket,
1563                  capabilities,
1564                  page_size));
1565 }
1566
1567 bool PrintPreviewHandler::CreatePrivetHTTP(
1568     const std::string& name,
1569     const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1570         callback) {
1571   const local_discovery::DeviceDescription* device_description =
1572       printer_lister_ ? printer_lister_->GetDeviceDescription(name) : NULL;
1573
1574   if (!device_description) {
1575     SendPrivetCapabilitiesError(name);
1576     return false;
1577   }
1578
1579   privet_http_factory_ =
1580       local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1581           service_discovery_client_.get(),
1582           Profile::FromWebUI(web_ui())->GetRequestContext());
1583   privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
1584       name, device_description->address, callback);
1585   privet_http_resolution_->Start();
1586
1587   return true;
1588 }
1589
1590 void PrintPreviewHandler::OnPrivetPrintingDone(
1591     const local_discovery::PrivetLocalPrintOperation* print_operation) {
1592   ClosePreviewDialog();
1593 }
1594
1595 void PrintPreviewHandler::OnPrivetPrintingError(
1596     const local_discovery::PrivetLocalPrintOperation* print_operation,
1597     int http_code) {
1598   base::FundamentalValue http_code_value(http_code);
1599   web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1600 }
1601
1602 void PrintPreviewHandler::FillPrinterDescription(
1603     const std::string& name,
1604     const local_discovery::DeviceDescription& description,
1605     bool has_local_printing,
1606     base::DictionaryValue* printer_value) {
1607   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1608
1609   printer_value->SetString("serviceName", name);
1610   printer_value->SetString("name", description.name);
1611   printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1612   printer_value->SetBoolean(
1613       "isUnregistered",
1614       description.id.empty() &&
1615       command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos));
1616   printer_value->SetString("cloudID", description.id);
1617 }
1618
1619 #endif  // defined(ENABLE_SERVICE_DISCOVERY)
1620
1621 void PrintPreviewHandler::RegisterForMergeSession() {
1622   DCHECK(!reconcilor_);
1623   Profile* profile = Profile::FromWebUI(web_ui());
1624   if (switches::IsEnableAccountConsistency() && !profile->IsOffTheRecord()) {
1625     reconcilor_ = AccountReconcilorFactory::GetForProfile(profile);
1626     if (reconcilor_)
1627       reconcilor_->AddMergeSessionObserver(this);
1628   }
1629 }
1630
1631 void PrintPreviewHandler::UnregisterForMergeSession() {
1632   if (reconcilor_)
1633     reconcilor_->RemoveMergeSessionObserver(this);
1634 }
1635
1636 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1637     const base::Closure& closure) {
1638   pdf_file_saved_closure_ = closure;
1639 }