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