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