Upstream version 11.40.277.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   gfx::NativeView GetParentView() override { return NULL; }
305   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   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   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(ENABLE_BASIC_PRINTING)
606   web_ui()->RegisterMessageCallback("showSystemDialog",
607       base::Bind(&PrintPreviewHandler::HandleShowSystemDialog,
608                  base::Unretained(this)));
609 #endif  // ENABLE_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("forceOpenNewTab",
638       base::Bind(&PrintPreviewHandler::HandleForceOpenNewTab,
639                  base::Unretained(this)));
640   web_ui()->RegisterMessageCallback("getPrivetPrinters",
641       base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinters,
642                  base::Unretained(this)));
643   web_ui()->RegisterMessageCallback("stopGetPrivetPrinters",
644       base::Bind(&PrintPreviewHandler::HandleStopGetPrivetPrinters,
645                  base::Unretained(this)));
646   web_ui()->RegisterMessageCallback("getPrivetPrinterCapabilities",
647       base::Bind(&PrintPreviewHandler::HandleGetPrivetPrinterCapabilities,
648                  base::Unretained(this)));
649   RegisterForMergeSession();
650 }
651
652 bool PrintPreviewHandler::PrivetPrintingEnabled() {
653 #if defined(ENABLE_SERVICE_DISCOVERY)
654   return true;
655 #else
656   return false;
657 #endif
658 }
659
660 WebContents* PrintPreviewHandler::preview_web_contents() const {
661   return web_ui()->GetWebContents();
662 }
663
664 void PrintPreviewHandler::HandleGetPrinters(const base::ListValue* /*args*/) {
665   base::ListValue* results = new base::ListValue;
666   BrowserThread::PostTaskAndReply(
667       BrowserThread::FILE, FROM_HERE,
668       base::Bind(&EnumeratePrintersOnFileThread,
669                  base::Unretained(results)),
670       base::Bind(&PrintPreviewHandler::SetupPrinterList,
671                  weak_factory_.GetWeakPtr(),
672                  base::Owned(results)));
673 }
674
675 void PrintPreviewHandler::HandleGetPrivetPrinters(const base::ListValue* args) {
676   if (!PrivetPrintingEnabled())
677     return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
678 #if defined(ENABLE_SERVICE_DISCOVERY)
679   local_discovery::ServiceDiscoverySharedClient::GetInstanceWithoutAlert(
680       base::Bind(&PrintPreviewHandler::StartPrivetLister,
681                  weak_factory_.GetWeakPtr()));
682 #endif  // ENABLE_SERVICE_DISCOVERY
683 }
684
685 void PrintPreviewHandler::HandleStopGetPrivetPrinters(
686     const base::ListValue* args) {
687 #if defined(ENABLE_SERVICE_DISCOVERY)
688   if (PrivetPrintingEnabled() && printer_lister_) {
689     printer_lister_->Stop();
690   }
691 #endif
692 }
693
694 void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
695     const base::ListValue* args) {
696 #if defined(ENABLE_SERVICE_DISCOVERY)
697   std::string name;
698   bool success = args->GetString(0, &name);
699   DCHECK(success);
700
701   CreatePrivetHTTP(
702       name,
703       base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
704                  base::Unretained(this)));
705 #endif
706 }
707
708 void PrintPreviewHandler::HandleGetPreview(const base::ListValue* args) {
709   DCHECK_EQ(3U, args->GetSize());
710   scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
711   if (!settings.get())
712     return;
713   int request_id = -1;
714   if (!settings->GetInteger(printing::kPreviewRequestID, &request_id))
715     return;
716
717   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
718       web_ui()->GetController());
719   print_preview_ui->OnPrintPreviewRequest(request_id);
720   // Add an additional key in order to identify |print_preview_ui| later on
721   // when calling PrintPreviewUI::GetCurrentPrintPreviewStatus() on the IO
722   // thread.
723   settings->SetInteger(printing::kPreviewUIID,
724                        print_preview_ui->GetIDForPrintPreviewUI());
725
726   // Increment request count.
727   ++regenerate_preview_request_count_;
728
729   WebContents* initiator = GetInitiator();
730   if (!initiator) {
731     ReportUserActionHistogram(INITIATOR_CLOSED);
732     print_preview_ui->OnClosePrintPreviewDialog();
733     return;
734   }
735
736   // Retrieve the page title and url and send it to the renderer process if
737   // headers and footers are to be displayed.
738   bool display_header_footer = false;
739   if (!settings->GetBoolean(printing::kSettingHeaderFooterEnabled,
740                             &display_header_footer)) {
741     NOTREACHED();
742   }
743   if (display_header_footer) {
744     settings->SetString(printing::kSettingHeaderFooterTitle,
745                         initiator->GetTitle());
746     std::string url;
747     content::NavigationEntry* entry =
748         initiator->GetController().GetLastCommittedEntry();
749     if (entry)
750       url = entry->GetVirtualURL().spec();
751     settings->SetString(printing::kSettingHeaderFooterURL, url);
752   }
753
754   bool generate_draft_data = false;
755   bool success = settings->GetBoolean(printing::kSettingGenerateDraftData,
756                                       &generate_draft_data);
757   DCHECK(success);
758
759   if (!generate_draft_data) {
760     double draft_page_count_double = -1;
761     success = args->GetDouble(1, &draft_page_count_double);
762     DCHECK(success);
763     int draft_page_count = static_cast<int>(draft_page_count_double);
764
765     bool preview_modifiable = false;
766     success = args->GetBoolean(2, &preview_modifiable);
767     DCHECK(success);
768
769     if (draft_page_count != -1 && preview_modifiable &&
770         print_preview_ui->GetAvailableDraftPageCount() != draft_page_count) {
771       settings->SetBoolean(printing::kSettingGenerateDraftData, true);
772     }
773   }
774
775   VLOG(1) << "Print preview request start";
776   RenderViewHost* rvh = initiator->GetRenderViewHost();
777   rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
778 }
779
780 void PrintPreviewHandler::HandlePrint(const base::ListValue* args) {
781   ReportStats();
782
783   // Record the number of times the user requests to regenerate preview data
784   // before printing.
785   UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforePrint",
786                        regenerate_preview_request_count_);
787
788   scoped_ptr<base::DictionaryValue> settings(GetSettingsDictionary(args));
789   if (!settings.get())
790     return;
791
792   ReportPrintSettingsStats(*settings);
793
794   // Never try to add headers/footers here. It's already in the generated PDF.
795   settings->SetBoolean(printing::kSettingHeaderFooterEnabled, false);
796
797   bool print_to_pdf = false;
798   bool is_cloud_printer = false;
799   bool print_with_privet = false;
800
801   bool open_pdf_in_preview = false;
802 #if defined(OS_MACOSX)
803   open_pdf_in_preview = settings->HasKey(printing::kSettingOpenPDFInPreview);
804 #endif
805
806   if (!open_pdf_in_preview) {
807     settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
808     settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
809     is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
810   }
811
812   int page_count = 0;
813   settings->GetInteger(printing::kSettingPreviewPageCount, &page_count);
814
815   if (print_to_pdf) {
816     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPDF", page_count);
817     ReportUserActionHistogram(PRINT_TO_PDF);
818     PrintToPdf();
819     return;
820   }
821
822 #if defined(ENABLE_SERVICE_DISCOVERY)
823   if (print_with_privet && PrivetPrintingEnabled()) {
824     std::string printer_name;
825     std::string print_ticket;
826     std::string capabilities;
827     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet", page_count);
828     ReportUserActionHistogram(PRINT_WITH_PRIVET);
829
830     int width = 0;
831     int height = 0;
832     if (!settings->GetString(printing::kSettingDeviceName, &printer_name) ||
833         !settings->GetString(printing::kSettingTicket, &print_ticket) ||
834         !settings->GetString(printing::kSettingCapabilities, &capabilities) ||
835         !settings->GetInteger(printing::kSettingPageWidth, &width) ||
836         !settings->GetInteger(printing::kSettingPageHeight, &height) ||
837         width <= 0 || height <= 0) {
838       NOTREACHED();
839       base::FundamentalValue http_code_value(-1);
840       web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
841       return;
842     }
843
844     PrintToPrivetPrinter(
845         printer_name, print_ticket, capabilities, gfx::Size(width, height));
846     return;
847   }
848 #endif
849
850   scoped_refptr<base::RefCountedBytes> data;
851   base::string16 title;
852   if (!GetPreviewDataAndTitle(&data, &title)) {
853     // Nothing to print, no preview available.
854     return;
855   }
856
857   if (is_cloud_printer) {
858     UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToCloudPrint",
859                          page_count);
860     ReportUserActionHistogram(PRINT_WITH_CLOUD_PRINT);
861     SendCloudPrintJob(data.get());
862   } else {
863     bool system_dialog = false;
864     settings->GetBoolean(printing::kSettingShowSystemDialog, &system_dialog);
865     if (system_dialog) {
866       UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", page_count);
867       ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
868     } else {
869       UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintToPrinter", page_count);
870       ReportUserActionHistogram(PRINT_TO_PRINTER);
871     }
872
873     // This tries to activate the initiator as well, so do not clear the
874     // association with the initiator yet.
875     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
876         web_ui()->GetController());
877     print_preview_ui->OnHidePreviewDialog();
878
879     // Do this so the initiator can open a new print preview dialog, while the
880     // current print preview dialog is still handling its print job.
881     WebContents* initiator = GetInitiator();
882     if (initiator) {
883       // Save initiator IDs. |PrintingMessageFilter::OnUpdatePrintSettings|
884       // would be called when initiator info is cleared.
885       settings->SetInteger(printing::kPreviewInitiatorHostId,
886                            initiator->GetRenderProcessHost()->GetID());
887       settings->SetInteger(printing::kPreviewInitiatorRoutingId,
888                            initiator->GetRoutingID());
889     }
890
891     ClearInitiatorDetails();
892
893     // The PDF being printed contains only the pages that the user selected,
894     // so ignore the page range and print all pages.
895     settings->Remove(printing::kSettingPageRange, NULL);
896     // Reset selection only flag for the same reason.
897     settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, false);
898
899     // Set ID to know whether printing is for preview.
900     settings->SetInteger(printing::kPreviewUIID,
901                          print_preview_ui->GetIDForPrintPreviewUI());
902     RenderViewHost* rvh = preview_web_contents()->GetRenderViewHost();
903     rvh->Send(new PrintMsg_PrintForPrintPreview(rvh->GetRoutingID(),
904                                                 *settings));
905
906     // For all other cases above, the preview dialog will stay open until the
907     // printing has finished. Then the dialog closes and PrintPreviewDone() gets
908     // called. In the case below, since the preview dialog will be hidden and
909     // not closed, we need to make this call.
910     if (initiator) {
911       printing::PrintViewManager* print_view_manager =
912           printing::PrintViewManager::FromWebContents(initiator);
913       print_view_manager->PrintPreviewDone();
914     }
915   }
916 }
917
918 void PrintPreviewHandler::PrintToPdf() {
919   if (!print_to_pdf_path_.empty()) {
920     // User has already selected a path, no need to show the dialog again.
921     PostPrintToPdfTask();
922   } else if (!select_file_dialog_.get() ||
923              !select_file_dialog_->IsRunning(platform_util::GetTopLevel(
924                  preview_web_contents()->GetNativeView()))) {
925     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
926         web_ui()->GetController());
927     // Pre-populating select file dialog with print job title.
928     base::string16 print_job_title_utf16 = print_preview_ui->initiator_title();
929
930 #if defined(OS_WIN)
931     base::FilePath::StringType print_job_title(print_job_title_utf16);
932 #elif defined(OS_POSIX)
933     base::FilePath::StringType print_job_title =
934         base::UTF16ToUTF8(print_job_title_utf16);
935 #endif
936
937     base::i18n::ReplaceIllegalCharactersInPath(&print_job_title, '_');
938     base::FilePath default_filename(print_job_title);
939     default_filename =
940         default_filename.ReplaceExtension(FILE_PATH_LITERAL("pdf"));
941
942     SelectFile(default_filename);
943   }
944 }
945
946 void PrintPreviewHandler::HandleHidePreview(const base::ListValue* /*args*/) {
947   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
948       web_ui()->GetController());
949   print_preview_ui->OnHidePreviewDialog();
950 }
951
952 void PrintPreviewHandler::HandleCancelPendingPrintRequest(
953     const base::ListValue* /*args*/) {
954   WebContents* initiator = GetInitiator();
955   if (initiator)
956     ClearInitiatorDetails();
957   chrome::ShowPrintErrorDialog();
958 }
959
960 void PrintPreviewHandler::HandleSaveAppState(const base::ListValue* args) {
961   std::string data_to_save;
962   printing::StickySettings* sticky_settings = GetStickySettings();
963   if (args->GetString(0, &data_to_save) && !data_to_save.empty())
964     sticky_settings->StoreAppState(data_to_save);
965   sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
966       preview_web_contents()->GetBrowserContext())->GetPrefs());
967 }
968
969 void PrintPreviewHandler::HandleGetPrinterCapabilities(
970     const base::ListValue* args) {
971   std::string printer_name;
972   bool ret = args->GetString(0, &printer_name);
973   if (!ret || printer_name.empty())
974     return;
975
976   GetPrinterCapabilitiesSuccessCallback success_cb =
977       base::Bind(&PrintPreviewHandler::SendPrinterCapabilities,
978                  weak_factory_.GetWeakPtr());
979   GetPrinterCapabilitiesFailureCallback failure_cb =
980       base::Bind(&PrintPreviewHandler::SendFailedToGetPrinterCapabilities,
981                  weak_factory_.GetWeakPtr());
982   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
983                           base::Bind(&GetPrinterCapabilitiesOnFileThread,
984                                      printer_name,
985                                      g_browser_process->GetApplicationLocale(),
986                                      success_cb, failure_cb));
987 }
988
989 void PrintPreviewHandler::OnSigninComplete() {
990   PrintPreviewUI* print_preview_ui =
991       static_cast<PrintPreviewUI*>(web_ui()->GetController());
992   if (print_preview_ui)
993     print_preview_ui->OnReloadPrintersList();
994 }
995
996 void PrintPreviewHandler::HandleSignin(const base::ListValue* args) {
997   bool add_account = false;
998   bool success = args->GetBoolean(0, &add_account);
999   DCHECK(success);
1000
1001   Profile* profile = Profile::FromBrowserContext(
1002       preview_web_contents()->GetBrowserContext());
1003   chrome::ScopedTabbedBrowserDisplayer displayer(
1004       profile, chrome::GetActiveDesktop());
1005   print_dialog_cloud::CreateCloudPrintSigninTab(
1006       displayer.browser(),
1007       add_account,
1008       base::Bind(&PrintPreviewHandler::OnSigninComplete,
1009                  weak_factory_.GetWeakPtr()));
1010 }
1011
1012 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
1013   std::string type;
1014   if (!args->GetString(0, &type))
1015     return;
1016   if (!token_service_)
1017     token_service_.reset(new AccessTokenService(this));
1018   token_service_->RequestToken(type);
1019 }
1020
1021 void PrintPreviewHandler::HandleManageCloudPrint(
1022     const base::ListValue* /*args*/) {
1023   ++manage_cloud_printers_dialog_request_count_;
1024   preview_web_contents()->OpenURL(content::OpenURLParams(
1025       cloud_devices::GetCloudPrintRelativeURL("manage.html"),
1026       content::Referrer(),
1027       NEW_FOREGROUND_TAB,
1028       ui::PAGE_TRANSITION_LINK,
1029       false));
1030 }
1031
1032 #if defined(ENABLE_BASIC_PRINTING)
1033 void PrintPreviewHandler::HandleShowSystemDialog(
1034     const base::ListValue* /*args*/) {
1035   ReportStats();
1036   ReportUserActionHistogram(FALLBACK_TO_ADVANCED_SETTINGS_DIALOG);
1037
1038   WebContents* initiator = GetInitiator();
1039   if (!initiator)
1040     return;
1041
1042   printing::PrintViewManager* print_view_manager =
1043       printing::PrintViewManager::FromWebContents(initiator);
1044   print_view_manager->set_observer(this);
1045   print_view_manager->PrintForSystemDialogNow();
1046
1047   // Cancel the pending preview request if exists.
1048   PrintPreviewUI* print_preview_ui =
1049       static_cast<PrintPreviewUI*>(web_ui()->GetController());
1050   print_preview_ui->OnCancelPendingPreviewRequest();
1051 }
1052 #endif  // ENABLE_BASIC_PRINTING
1053
1054 void PrintPreviewHandler::HandleManagePrinters(
1055     const base::ListValue* /*args*/) {
1056   ++manage_printers_dialog_request_count_;
1057   printing::PrinterManagerDialog::ShowPrinterManagerDialog();
1058 }
1059
1060 void PrintPreviewHandler::HandleClosePreviewDialog(
1061     const base::ListValue* /*args*/) {
1062   ReportStats();
1063   ReportUserActionHistogram(CANCEL);
1064
1065   // Record the number of times the user requests to regenerate preview data
1066   // before cancelling.
1067   UMA_HISTOGRAM_COUNTS("PrintPreview.RegeneratePreviewRequest.BeforeCancel",
1068                        regenerate_preview_request_count_);
1069 }
1070
1071 void PrintPreviewHandler::ReportStats() {
1072   UMA_HISTOGRAM_COUNTS("PrintPreview.ManagePrinters",
1073                        manage_printers_dialog_request_count_);
1074   UMA_HISTOGRAM_COUNTS("PrintPreview.ManageCloudPrinters",
1075                        manage_cloud_printers_dialog_request_count_);
1076 }
1077
1078 void PrintPreviewHandler::GetNumberFormatAndMeasurementSystem(
1079     base::DictionaryValue* settings) {
1080
1081   // Getting the measurement system based on the locale.
1082   UErrorCode errorCode = U_ZERO_ERROR;
1083   const char* locale = g_browser_process->GetApplicationLocale().c_str();
1084   UMeasurementSystem system = ulocdata_getMeasurementSystem(locale, &errorCode);
1085   if (errorCode > U_ZERO_ERROR || system == UMS_LIMIT)
1086     system = UMS_SI;
1087
1088   // Getting the number formatting based on the locale and writing to
1089   // dictionary.
1090   settings->SetString(kNumberFormat, base::FormatDouble(123456.78, 2));
1091   settings->SetInteger(kMeasurementSystem, system);
1092 }
1093
1094 void PrintPreviewHandler::HandleGetInitialSettings(
1095     const base::ListValue* /*args*/) {
1096   // Send before SendInitialSettings to allow cloud printer auto select.
1097   SendCloudPrintEnabled();
1098   BrowserThread::PostTaskAndReplyWithResult(
1099       BrowserThread::FILE, FROM_HERE,
1100       base::Bind(&GetDefaultPrinterOnFileThread),
1101       base::Bind(&PrintPreviewHandler::SendInitialSettings,
1102                  weak_factory_.GetWeakPtr()));
1103 }
1104
1105 void PrintPreviewHandler::HandleForceOpenNewTab(const base::ListValue* args) {
1106   std::string url;
1107   if (!args->GetString(0, &url))
1108     return;
1109   Browser* browser = chrome::FindBrowserWithWebContents(GetInitiator());
1110   if (!browser)
1111     return;
1112   chrome::AddSelectedTabWithURL(browser,
1113                                 GURL(url),
1114                                 ui::PAGE_TRANSITION_LINK);
1115 }
1116
1117 void PrintPreviewHandler::SendInitialSettings(
1118     const std::string& default_printer) {
1119   PrintPreviewUI* print_preview_ui =
1120       static_cast<PrintPreviewUI*>(web_ui()->GetController());
1121
1122   base::DictionaryValue initial_settings;
1123   initial_settings.SetString(kInitiatorTitle,
1124                              print_preview_ui->initiator_title());
1125   initial_settings.SetBoolean(printing::kSettingPreviewModifiable,
1126                               print_preview_ui->source_is_modifiable());
1127   initial_settings.SetString(printing::kSettingPrinterName, default_printer);
1128   initial_settings.SetBoolean(kDocumentHasSelection,
1129                               print_preview_ui->source_has_selection());
1130   initial_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly,
1131                               print_preview_ui->print_selection_only());
1132   printing::StickySettings* sticky_settings = GetStickySettings();
1133   sticky_settings->RestoreFromPrefs(Profile::FromBrowserContext(
1134       preview_web_contents()->GetBrowserContext())->GetPrefs());
1135   if (sticky_settings->printer_app_state()) {
1136     initial_settings.SetString(kAppState,
1137                                *sticky_settings->printer_app_state());
1138   }
1139
1140   base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
1141   initial_settings.SetBoolean(kPrintAutomaticallyInKioskMode,
1142                               cmdline->HasSwitch(switches::kKioskModePrinting));
1143   initial_settings.SetBoolean(kAppKioskMode,
1144                               chrome::IsRunningInForcedAppMode());
1145 #if defined(OS_WIN)
1146   // In Win8 metro, the system print dialog can only open on the desktop.  Doing
1147   // so will cause the browser to appear hung, so we don't show the link in
1148   // metro.
1149   bool is_ash = (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH);
1150   initial_settings.SetBoolean(kHidePrintWithSystemDialogLink, is_ash);
1151 #endif
1152
1153   if (print_preview_ui->source_is_modifiable())
1154     GetNumberFormatAndMeasurementSystem(&initial_settings);
1155   web_ui()->CallJavascriptFunction("setInitialSettings", initial_settings);
1156 }
1157
1158 void PrintPreviewHandler::ClosePreviewDialog() {
1159   PrintPreviewUI* print_preview_ui =
1160       static_cast<PrintPreviewUI*>(web_ui()->GetController());
1161   print_preview_ui->OnClosePrintPreviewDialog();
1162 }
1163
1164 void PrintPreviewHandler::SendAccessToken(const std::string& type,
1165                                           const std::string& access_token) {
1166   VLOG(1) << "Get getAccessToken finished";
1167   web_ui()->CallJavascriptFunction("onDidGetAccessToken",
1168                                    base::StringValue(type),
1169                                    base::StringValue(access_token));
1170 }
1171
1172 void PrintPreviewHandler::SendPrinterCapabilities(
1173     const base::DictionaryValue* settings_info) {
1174   VLOG(1) << "Get printer capabilities finished";
1175   web_ui()->CallJavascriptFunction("updateWithPrinterCapabilities",
1176                                    *settings_info);
1177 }
1178
1179 void PrintPreviewHandler::SendFailedToGetPrinterCapabilities(
1180     const std::string& printer_name) {
1181   VLOG(1) << "Get printer capabilities failed";
1182   base::StringValue printer_name_value(printer_name);
1183   web_ui()->CallJavascriptFunction("failedToGetPrinterCapabilities",
1184                                    printer_name_value);
1185 }
1186
1187 void PrintPreviewHandler::SetupPrinterList(const base::ListValue* printers) {
1188   if (!has_logged_printers_count_) {
1189     UMA_HISTOGRAM_COUNTS("PrintPreview.NumberOfPrinters", printers->GetSize());
1190     has_logged_printers_count_ = true;
1191   }
1192
1193   web_ui()->CallJavascriptFunction("setPrinters", *printers);
1194 }
1195
1196 void PrintPreviewHandler::SendCloudPrintEnabled() {
1197   Profile* profile = Profile::FromBrowserContext(
1198       preview_web_contents()->GetBrowserContext());
1199   PrefService* prefs = profile->GetPrefs();
1200   if (prefs->GetBoolean(prefs::kCloudPrintSubmitEnabled)) {
1201     base::DictionaryValue settings;
1202     settings.SetString(kCloudPrintUrl,
1203                        GURL(cloud_devices::GetCloudPrintURL()).spec());
1204     settings.SetBoolean(kAppKioskMode, chrome::IsRunningInForcedAppMode());
1205     web_ui()->CallJavascriptFunction("setUseCloudPrint", settings);
1206   }
1207 }
1208
1209 void PrintPreviewHandler::SendCloudPrintJob(const base::RefCountedBytes* data) {
1210   // BASE64 encode the job data.
1211   std::string raw_data(reinterpret_cast<const char*>(data->front()),
1212                        data->size());
1213   std::string base64_data;
1214   base::Base64Encode(raw_data, &base64_data);
1215   base::StringValue data_value(base64_data);
1216
1217   web_ui()->CallJavascriptFunction("printToCloud", data_value);
1218 }
1219
1220 WebContents* PrintPreviewHandler::GetInitiator() const {
1221   printing::PrintPreviewDialogController* dialog_controller =
1222       printing::PrintPreviewDialogController::GetInstance();
1223   if (!dialog_controller)
1224     return NULL;
1225   return dialog_controller->GetInitiator(preview_web_contents());
1226 }
1227
1228 void PrintPreviewHandler::OnPrintDialogShown() {
1229   ClosePreviewDialog();
1230 }
1231
1232 void PrintPreviewHandler::MergeSessionCompleted(
1233     const std::string& account_id,
1234     const GoogleServiceAuthError& error) {
1235   OnSigninComplete();
1236 }
1237
1238 void PrintPreviewHandler::SelectFile(const base::FilePath& default_filename) {
1239   ui::SelectFileDialog::FileTypeInfo file_type_info;
1240   file_type_info.extensions.resize(1);
1241   file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
1242
1243   // Initializing |save_path_| if it is not already initialized.
1244   printing::StickySettings* sticky_settings = GetStickySettings();
1245   if (!sticky_settings->save_path()) {
1246     // Allowing IO operation temporarily. It is ok to do so here because
1247     // the select file dialog performs IO anyway in order to display the
1248     // folders and also it is modal.
1249     base::ThreadRestrictions::ScopedAllowIO allow_io;
1250     base::FilePath file_path;
1251     PathService::Get(chrome::DIR_USER_DOCUMENTS, &file_path);
1252     sticky_settings->StoreSavePath(file_path);
1253     sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1254         preview_web_contents()->GetBrowserContext())->GetPrefs());
1255   }
1256
1257   select_file_dialog_ = ui::SelectFileDialog::Create(
1258       this, new ChromeSelectFilePolicy(preview_web_contents())),
1259   select_file_dialog_->SelectFile(
1260       ui::SelectFileDialog::SELECT_SAVEAS_FILE,
1261       base::string16(),
1262       sticky_settings->save_path()->Append(default_filename),
1263       &file_type_info,
1264       0,
1265       base::FilePath::StringType(),
1266       platform_util::GetTopLevel(preview_web_contents()->GetNativeView()),
1267       NULL);
1268 }
1269
1270 void PrintPreviewHandler::OnPrintPreviewDialogDestroyed() {
1271   WebContents* initiator = GetInitiator();
1272   if (!initiator)
1273     return;
1274
1275   printing::PrintViewManager* print_view_manager =
1276       printing::PrintViewManager::FromWebContents(initiator);
1277   print_view_manager->set_observer(NULL);
1278 }
1279
1280 void PrintPreviewHandler::OnPrintPreviewFailed() {
1281   if (reported_failed_preview_)
1282     return;
1283   reported_failed_preview_ = true;
1284   ReportUserActionHistogram(PREVIEW_FAILED);
1285 }
1286
1287 #if defined(ENABLE_BASIC_PRINTING)
1288 void PrintPreviewHandler::ShowSystemDialog() {
1289   HandleShowSystemDialog(NULL);
1290 }
1291 #endif  // ENABLE_BASIC_PRINTING
1292
1293 void PrintPreviewHandler::FileSelected(const base::FilePath& path,
1294                                        int index, void* params) {
1295   // Updating |save_path_| to the newly selected folder.
1296   printing::StickySettings* sticky_settings = GetStickySettings();
1297   sticky_settings->StoreSavePath(path.DirName());
1298   sticky_settings->SaveInPrefs(Profile::FromBrowserContext(
1299       preview_web_contents()->GetBrowserContext())->GetPrefs());
1300   web_ui()->CallJavascriptFunction("fileSelectionCompleted");
1301   print_to_pdf_path_ = path;
1302   PostPrintToPdfTask();
1303 }
1304
1305 void PrintPreviewHandler::PostPrintToPdfTask() {
1306   scoped_refptr<base::RefCountedBytes> data;
1307   base::string16 title;
1308   if (!GetPreviewDataAndTitle(&data, &title)) {
1309     NOTREACHED() << "Preview data was checked before file dialog.";
1310     return;
1311   }
1312   BrowserThread::PostTask(BrowserThread::FILE,
1313                           FROM_HERE,
1314                           base::Bind(&PrintToPdfCallback,
1315                                      data,
1316                                      print_to_pdf_path_,
1317                                      pdf_file_saved_closure_));
1318   print_to_pdf_path_ = base::FilePath();
1319   ClosePreviewDialog();
1320 }
1321
1322 void PrintPreviewHandler::FileSelectionCanceled(void* params) {
1323   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1324       web_ui()->GetController());
1325   print_preview_ui->OnFileSelectionCancelled();
1326 }
1327
1328 void PrintPreviewHandler::ClearInitiatorDetails() {
1329   WebContents* initiator = GetInitiator();
1330   if (!initiator)
1331     return;
1332
1333   // We no longer require the initiator details. Remove those details associated
1334   // with the preview dialog to allow the initiator to create another preview
1335   // dialog.
1336   printing::PrintPreviewDialogController* dialog_controller =
1337       printing::PrintPreviewDialogController::GetInstance();
1338   if (dialog_controller)
1339     dialog_controller->EraseInitiatorInfo(preview_web_contents());
1340 }
1341
1342 bool PrintPreviewHandler::GetPreviewDataAndTitle(
1343     scoped_refptr<base::RefCountedBytes>* data,
1344     base::string16* title) const {
1345   PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
1346       web_ui()->GetController());
1347   scoped_refptr<base::RefCountedBytes> tmp_data;
1348   print_preview_ui->GetPrintPreviewDataForIndex(
1349       printing::COMPLETE_PREVIEW_DOCUMENT_INDEX, &tmp_data);
1350
1351   if (!tmp_data.get()) {
1352     // Nothing to print, no preview available.
1353     return false;
1354   }
1355   DCHECK(tmp_data->size() && tmp_data->front());
1356
1357   *data = tmp_data;
1358   *title = print_preview_ui->initiator_title();
1359   return true;
1360 }
1361
1362 #if defined(ENABLE_SERVICE_DISCOVERY)
1363
1364 void PrintPreviewHandler::StartPrivetLister(const scoped_refptr<
1365     local_discovery::ServiceDiscoverySharedClient>& client) {
1366   if (!PrivetPrintingEnabled())
1367     return web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
1368
1369   Profile* profile = Profile::FromWebUI(web_ui());
1370   DCHECK(!service_discovery_client_.get() ||
1371          service_discovery_client_.get() == client.get());
1372   service_discovery_client_ = client;
1373   printer_lister_.reset(new local_discovery::PrivetLocalPrinterLister(
1374       service_discovery_client_.get(), profile->GetRequestContext(), this));
1375   printer_lister_->Start();
1376 }
1377
1378 void PrintPreviewHandler::LocalPrinterChanged(
1379     bool added,
1380     const std::string& name,
1381     bool has_local_printing,
1382     const local_discovery::DeviceDescription& description) {
1383   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1384   if (has_local_printing ||
1385       command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos)) {
1386     base::DictionaryValue info;
1387     FillPrinterDescription(name, description, has_local_printing, &info);
1388     web_ui()->CallJavascriptFunction("onPrivetPrinterChanged", info);
1389   }
1390 }
1391
1392 void PrintPreviewHandler::LocalPrinterRemoved(const std::string& name) {
1393 }
1394
1395 void PrintPreviewHandler::LocalPrinterCacheFlushed() {
1396 }
1397
1398 void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
1399     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1400   if (!PrivetUpdateClient(http_client.Pass()))
1401     return;
1402
1403   privet_capabilities_operation_ =
1404       privet_http_client_->CreateCapabilitiesOperation(
1405           base::Bind(&PrintPreviewHandler::OnPrivetCapabilities,
1406                      base::Unretained(this)));
1407   privet_capabilities_operation_->Start();
1408 }
1409
1410 bool PrintPreviewHandler::PrivetUpdateClient(
1411     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1412   if (!http_client) {
1413     SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
1414     privet_http_resolution_.reset();
1415     return false;
1416   }
1417
1418   privet_local_print_operation_.reset();
1419   privet_capabilities_operation_.reset();
1420   privet_http_client_ =
1421       local_discovery::PrivetV1HTTPClient::CreateDefault(http_client.Pass());
1422
1423   privet_http_resolution_.reset();
1424
1425   return true;
1426 }
1427
1428 void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
1429     std::string print_ticket,
1430     std::string capabilities,
1431     gfx::Size page_size,
1432     scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
1433   if (!PrivetUpdateClient(http_client.Pass()))
1434     return;
1435
1436   StartPrivetLocalPrint(print_ticket, capabilities, page_size);
1437 }
1438
1439 void PrintPreviewHandler::StartPrivetLocalPrint(const std::string& print_ticket,
1440                                                 const std::string& capabilities,
1441                                                 const gfx::Size& page_size) {
1442   privet_local_print_operation_ =
1443       privet_http_client_->CreateLocalPrintOperation(this);
1444
1445   privet_local_print_operation_->SetTicket(print_ticket);
1446   privet_local_print_operation_->SetCapabilities(capabilities);
1447
1448   scoped_refptr<base::RefCountedBytes> data;
1449   base::string16 title;
1450
1451   if (!GetPreviewDataAndTitle(&data, &title)) {
1452     base::FundamentalValue http_code_value(-1);
1453     web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1454     return;
1455   }
1456
1457   privet_local_print_operation_->SetJobname(base::UTF16ToUTF8(title));
1458   privet_local_print_operation_->SetPageSize(page_size);
1459   privet_local_print_operation_->SetData(data.get());
1460
1461   Profile* profile = Profile::FromWebUI(web_ui());
1462   SigninManagerBase* signin_manager =
1463       SigninManagerFactory::GetForProfileIfExists(profile);
1464
1465   if (signin_manager) {
1466     privet_local_print_operation_->SetUsername(
1467         signin_manager->GetAuthenticatedUsername());
1468   }
1469
1470   privet_local_print_operation_->Start();
1471 }
1472
1473
1474 void PrintPreviewHandler::OnPrivetCapabilities(
1475     const base::DictionaryValue* capabilities) {
1476   std::string name = privet_capabilities_operation_->GetHTTPClient()->GetName();
1477
1478   if (!capabilities || capabilities->HasKey(local_discovery::kPrivetKeyError) ||
1479       !printer_lister_) {
1480     SendPrivetCapabilitiesError(name);
1481     return;
1482   }
1483
1484   base::DictionaryValue printer_info;
1485   const local_discovery::DeviceDescription* description =
1486       printer_lister_->GetDeviceDescription(name);
1487
1488   if (!description) {
1489     SendPrivetCapabilitiesError(name);
1490     return;
1491   }
1492
1493   FillPrinterDescription(name, *description, true, &printer_info);
1494
1495   web_ui()->CallJavascriptFunction(
1496       "onPrivetCapabilitiesSet",
1497       printer_info,
1498       *capabilities);
1499
1500   privet_capabilities_operation_.reset();
1501 }
1502
1503 void PrintPreviewHandler::SendPrivetCapabilitiesError(
1504     const std::string& device_name) {
1505   base::StringValue name_value(device_name);
1506   web_ui()->CallJavascriptFunction(
1507       "failedToGetPrivetPrinterCapabilities",
1508       name_value);
1509 }
1510
1511 void PrintPreviewHandler::PrintToPrivetPrinter(const std::string& device_name,
1512                                                const std::string& ticket,
1513                                                const std::string& capabilities,
1514                                                const gfx::Size& page_size) {
1515   CreatePrivetHTTP(
1516       device_name,
1517       base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
1518                  base::Unretained(this),
1519                  ticket,
1520                  capabilities,
1521                  page_size));
1522 }
1523
1524 bool PrintPreviewHandler::CreatePrivetHTTP(
1525     const std::string& name,
1526     const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
1527         callback) {
1528   const local_discovery::DeviceDescription* device_description =
1529       printer_lister_ ? printer_lister_->GetDeviceDescription(name) : NULL;
1530
1531   if (!device_description) {
1532     SendPrivetCapabilitiesError(name);
1533     return false;
1534   }
1535
1536   privet_http_factory_ =
1537       local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
1538           service_discovery_client_.get(),
1539           Profile::FromWebUI(web_ui())->GetRequestContext());
1540   privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
1541       name, device_description->address, callback);
1542   privet_http_resolution_->Start();
1543
1544   return true;
1545 }
1546
1547 void PrintPreviewHandler::OnPrivetPrintingDone(
1548     const local_discovery::PrivetLocalPrintOperation* print_operation) {
1549   ClosePreviewDialog();
1550 }
1551
1552 void PrintPreviewHandler::OnPrivetPrintingError(
1553     const local_discovery::PrivetLocalPrintOperation* print_operation,
1554     int http_code) {
1555   base::FundamentalValue http_code_value(http_code);
1556   web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
1557 }
1558
1559 void PrintPreviewHandler::FillPrinterDescription(
1560     const std::string& name,
1561     const local_discovery::DeviceDescription& description,
1562     bool has_local_printing,
1563     base::DictionaryValue* printer_value) {
1564   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
1565
1566   printer_value->SetString("serviceName", name);
1567   printer_value->SetString("name", description.name);
1568   printer_value->SetBoolean("hasLocalPrinting", has_local_printing);
1569   printer_value->SetBoolean(
1570       "isUnregistered",
1571       description.id.empty() &&
1572       command_line->HasSwitch(switches::kEnablePrintPreviewRegisterPromos));
1573   printer_value->SetString("cloudID", description.id);
1574 }
1575
1576 #endif  // defined(ENABLE_SERVICE_DISCOVERY)
1577
1578 void PrintPreviewHandler::RegisterForMergeSession() {
1579   DCHECK(!reconcilor_);
1580   Profile* profile = Profile::FromWebUI(web_ui());
1581   if (switches::IsEnableAccountConsistency() && !profile->IsOffTheRecord()) {
1582     reconcilor_ = AccountReconcilorFactory::GetForProfile(profile);
1583     if (reconcilor_)
1584       reconcilor_->AddMergeSessionObserver(this);
1585   }
1586 }
1587
1588 void PrintPreviewHandler::UnregisterForMergeSession() {
1589   if (reconcilor_)
1590     reconcilor_->RemoveMergeSessionObserver(this);
1591 }
1592
1593 void PrintPreviewHandler::SetPdfSavedClosureForTesting(
1594     const base::Closure& closure) {
1595   pdf_file_saved_closure_ = closure;
1596 }