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