0

Print to Privet local printers

This is a first iteration of printing to a Privet local printer. It only
supports PDFs. PWG rasterization will be added separately.

BUG=311390

Review URL: https://codereview.chromium.org/59843010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@234126 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
noamsml@chromium.org
2013-11-09 17:23:25 +00:00
parent 901cf6ff7f
commit 014a62cbb9
11 changed files with 241 additions and 33 deletions

@ -8691,6 +8691,9 @@ The following plug-in is unresponsive: <ph name="PLUGIN_NAME">$1
<message name="IDS_PRINT_PREVIEW_NO_DESTS_PROMO_NOT_NOW_BUTTON_LABEL" desc="Label of button to cancel the Google Cloud Print promotion.">
Not now
</message>
<message name="IDS_PRINT_PREVIEW_COULD_NOT_PRINT" desc="Error message when printing fails in the print preview">
Printing failed. Please check your printer and try again.
</message>
<!-- Load State -->
<message name="IDS_LOAD_STATE_WAITING_FOR_SOCKET_SLOT" desc="Status text when Chrome is at its connection limit, and is waiting for a URL request to complete to free up a connection.">

@ -680,7 +680,8 @@ cr.define('print_preview', function() {
dest.capabilities = event.capabilities;
this.updateDestination(dest);
if (this.selectedDestination_ == dest) {
if (this.selectedDestination_.isPrivet &&
this.selectedDestination_.id == dest.id) {
cr.dispatchSimpleEvent(
this,
DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY);

@ -337,9 +337,10 @@ cr.define('print_preview', function() {
* @return {!Object} Google Cloud Print print ticket.
*/
createPrintTicket: function(destination) {
assert(!destination.isLocal,
assert(!destination.isLocal || destination.isPrivet,
'Trying to create a Google Cloud Print print ticket for a local ' +
'destination');
' non-privet destination');
assert(destination.capabilities,
'Trying to create a Google Cloud Print print ticket for a ' +
'destination with no print capabilities');

@ -48,6 +48,7 @@ cr.define('print_preview', function() {
this.onPrivetPrinterSearchDone_.bind(this);
global['onPrivetCapabilitiesSet'] =
this.onPrivetCapabilitiesSet_.bind(this);
global['onPrivetPrintFailed'] = this.onPrivetPrintFailed_.bind(this);
};
/**
@ -81,7 +82,8 @@ cr.define('print_preview', function() {
PRIVET_PRINTER_SEARCH_DONE:
'print_preview.NativeLayer.PRIVET_PRINTER_SEARCH_DONE',
PRIVET_CAPABILITIES_SET:
'print_preview.NativeLayer.PRIVET_CAPABILITIES_SET'
'print_preview.NativeLayer.PRIVET_CAPABILITIES_SET',
PRIVET_PRINT_FAILED: 'print_preview.NativeLayer.PRIVET_PRINT_FAILED'
};
/**
@ -273,6 +275,7 @@ cr.define('print_preview', function() {
'printToPDF': destination.id ==
print_preview.Destination.GooglePromotedId.SAVE_AS_PDF,
'printWithCloudPrint': !destination.isLocal,
'printWithPrivet': destination.isPrivet,
'deviceName': destination.id,
'isFirstRequest': false,
'requestID': -1,
@ -300,6 +303,10 @@ cr.define('print_preview', function() {
};
}
if (destination.isPrivet) {
ticket['ticket'] = printTicketStore.createPrintTicket(destination);
}
if (opt_isOpenPdfInPreview) {
ticket['OpenPDFInPreview'] = true;
}
@ -654,8 +661,8 @@ cr.define('print_preview', function() {
* @private
*/
onPrivetPrinterSearchDone_: function() {
var privetPrinterSearchDoneEvent = new Event(
NativeLayer.EventType.PRIVET_PRINTER_SEARCH_DONE);
var privetPrinterSearchDoneEvent =
new Event(NativeLayer.EventType.PRIVET_PRINTER_SEARCH_DONE);
this.dispatchEvent(privetPrinterSearchDoneEvent);
},
@ -665,11 +672,23 @@ cr.define('print_preview', function() {
* @private
*/
onPrivetCapabilitiesSet_: function(printer, capabilities) {
var privetCapabilitiesSetEvent = new Event(
NativeLayer.EventType.PRIVET_CAPABILITIES_SET);
var privetCapabilitiesSetEvent =
new Event(NativeLayer.EventType.PRIVET_CAPABILITIES_SET);
privetCapabilitiesSetEvent.printer = printer;
privetCapabilitiesSetEvent.capabilities = capabilities;
this.dispatchEvent(privetCapabilitiesSetEvent);
},
/**
* @param {string} http_error The HTTP response code or -1 if not an HTTP
* error.
* @private
*/
onPrivetPrintFailed_: function(http_error) {
var privetPrintFailedEvent =
new Event(NativeLayer.EventType.PRIVET_PRINT_FAILED);
privetPrintFailedEvent.httpError = http_error;
this.dispatchEvent(privetPrintFailedEvent);
}
};

@ -260,6 +260,11 @@ cr.define('print_preview', function() {
this.nativeLayer_,
print_preview.NativeLayer.EventType.DISABLE_SCALING,
this.onDisableScaling_.bind(this));
this.tracker.add(
this.nativeLayer_,
print_preview.NativeLayer.EventType.PRIVET_PRINT_FAILED,
this.onPrivetPrintFailed_.bind(this));
this.tracker.add(
$('system-dialog-link'),
@ -406,6 +411,7 @@ cr.define('print_preview', function() {
this.setIsEnabled_(false);
if (this.printIfReady_() &&
((this.destinationStore_.selectedDestination.isLocal &&
!this.destinationStore_.selectedDestination.isPrivet &&
this.destinationStore_.selectedDestination.id !=
print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) ||
this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW)) {
@ -802,6 +808,18 @@ cr.define('print_preview', function() {
this.documentInfo_.updateIsScalingDisabled(true);
},
/**
* Called when privet printing fails.
* @param {Event} event Event object representing the failure.
* @private
*/
onPrivetPrintFailed_: function(event) {
console.error('Privet printing failed with error code ' +
event.httpError);
this.printHeader_.setErrorMessage(
localStrings.getString('couldNotPrint'));
},
/**
* Called when the open-cloud-print-dialog link is clicked. Opens the Google
* Cloud Print web dialog.

@ -37,6 +37,9 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/profile_oauth2_token_service.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_base.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
@ -88,6 +91,7 @@ enum UserActionBuckets {
INITIATOR_CRASHED, // UNUSED
INITIATOR_CLOSED,
PRINT_WITH_CLOUD_PRINT,
PRINT_WITH_PRIVET,
USERACTION_BUCKET_BOUNDARY
};
@ -602,24 +606,10 @@ void PrintPreviewHandler::HandleGetPrivetPrinterCapabilities(
bool success = args->GetString(0, &name);
DCHECK(success);
const local_discovery::DeviceDescription* device_description =
printer_lister_->GetDeviceDescription(name);
if (!device_description) {
SendPrivetCapabilitiesError(name);
return;
}
privet_http_factory_ =
local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
service_discovery_client_,
Profile::FromWebUI(web_ui())->GetRequestContext());
privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
CreatePrivetHTTP(
name,
device_description->address,
base::Bind(&PrintPreviewHandler::StartPrivetCapabilities,
base::Bind(&PrintPreviewHandler::PrivetCapabilitiesUpdateClient,
base::Unretained(this)));
privet_http_resolution_->Start();
#endif
}
@ -718,6 +708,7 @@ void PrintPreviewHandler::HandlePrint(const ListValue* args) {
bool print_to_pdf = false;
bool is_cloud_printer = false;
bool print_with_privet = false;
bool open_pdf_in_preview = false;
#if defined(OS_MACOSX)
@ -726,6 +717,7 @@ void PrintPreviewHandler::HandlePrint(const ListValue* args) {
if (!open_pdf_in_preview) {
settings->GetBoolean(printing::kSettingPrintToPDF, &print_to_pdf);
settings->GetBoolean(printing::kSettingPrintWithPrivet, &print_with_privet);
is_cloud_printer = settings->HasKey(printing::kSettingCloudPrintId);
}
@ -739,6 +731,26 @@ void PrintPreviewHandler::HandlePrint(const ListValue* args) {
return;
}
#if defined(ENABLE_MDNS)
if (print_with_privet && PrivetPrintingEnabled()) {
std::string printer_name;
std::string print_ticket;
UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.PrintWithPrivet",
page_count);
ReportUserActionHistogram(PRINT_WITH_PRIVET);
bool success = settings->GetString(printing::kSettingDeviceName,
&printer_name);
DCHECK(success);
success = settings->GetString(printing::kSettingTicket,
&print_ticket);
DCHECK(success);
PrintToPrivetPrinter(printer_name, print_ticket);
return;
}
#endif
scoped_refptr<base::RefCountedBytes> data;
string16 title;
if (!GetPreviewDataAndTitle(&data, &title)) {
@ -1366,22 +1378,68 @@ void PrintPreviewHandler::StopPrivetPrinterSearch() {
web_ui()->CallJavascriptFunction("onPrivetPrinterSearchDone");
}
void PrintPreviewHandler::StartPrivetCapabilities(
void PrintPreviewHandler::PrivetCapabilitiesUpdateClient(
scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
if (!PrivetUpdateClient(http_client.Pass()))
return;
privet_capabilities_operation_ =
privet_http_client_->CreateCapabilitiesOperation(
this);
privet_capabilities_operation_->Start();
}
bool PrintPreviewHandler::PrivetUpdateClient(
scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
if (!http_client) {
SendPrivetCapabilitiesError(privet_http_resolution_->GetName());
privet_http_resolution_.reset();
return;
return false;
}
privet_local_print_operation_.reset();
privet_capabilities_operation_.reset();
privet_http_client_ = http_client.Pass();
privet_capabilities_operation_ =
privet_http_client_->CreateCapabilitiesOperation(
this);
privet_http_resolution_.reset();
privet_capabilities_operation_->Start();
return true;
}
void PrintPreviewHandler::PrivetLocalPrintUpdateClient(
std::string print_ticket,
scoped_ptr<local_discovery::PrivetHTTPClient> http_client) {
if (!PrivetUpdateClient(http_client.Pass()))
return;
StartPrivetLocalPrint(print_ticket);
}
void PrintPreviewHandler::StartPrivetLocalPrint(
const std::string& print_ticket) {
privet_local_print_operation_ =
privet_http_client_->CreateLocalPrintOperation(this);
privet_local_print_operation_->SetTicket(print_ticket);
PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
web_ui()->GetController());
privet_local_print_operation_->SetJobname(
base::UTF16ToUTF8(print_preview_ui->initiator_title()));
Profile* profile = Profile::FromWebUI(web_ui());
SigninManagerBase* signin_manager =
SigninManagerFactory::GetForProfileIfExists(profile);
if (signin_manager) {
privet_local_print_operation_->SetUsername(
signin_manager->GetAuthenticatedUsername());
}
privet_local_print_operation_->Start();
}
void PrintPreviewHandler::OnPrivetCapabilities(
local_discovery::PrivetCapabilitiesOperation* capabilities_operation,
int http_error,
@ -1420,6 +1478,75 @@ void PrintPreviewHandler::SendPrivetCapabilitiesError(
name_value);
}
void PrintPreviewHandler::PrintToPrivetPrinter(
const std::string& device_name,
const std::string& ticket) {
CreatePrivetHTTP(
device_name,
base::Bind(&PrintPreviewHandler::PrivetLocalPrintUpdateClient,
base::Unretained(this),
ticket));
}
bool PrintPreviewHandler::CreatePrivetHTTP(
const std::string& name,
const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
callback) {
const local_discovery::DeviceDescription* device_description =
printer_lister_->GetDeviceDescription(name);
if (!device_description) {
SendPrivetCapabilitiesError(name);
return false;
}
privet_http_factory_ =
local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
service_discovery_client_,
Profile::FromWebUI(web_ui())->GetRequestContext());
privet_http_resolution_ = privet_http_factory_->CreatePrivetHTTP(
name,
device_description->address,
callback);
privet_http_resolution_->Start();
return true;
}
void PrintPreviewHandler::OnPrivetPrintingRequestPDF(
const local_discovery::PrivetLocalPrintOperation* print_operation) {
scoped_refptr<base::RefCountedBytes> data;
string16 title;
if (!GetPreviewDataAndTitle(&data, &title)) {
base::FundamentalValue http_code_value(-1);
web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
return;
}
// TODO(noamsml): Move data into request without copying it?
std::string data_str((const char*)data->front(), data->size());
privet_local_print_operation_->SendData(data_str);
}
void PrintPreviewHandler::OnPrivetPrintingRequestPWGRaster(
const local_discovery::PrivetLocalPrintOperation* print_operation) {
NOTIMPLEMENTED();
}
void PrintPreviewHandler::OnPrivetPrintingDone(
const local_discovery::PrivetLocalPrintOperation* print_operation) {
ClosePreviewDialog();
}
void PrintPreviewHandler::OnPrivetPrintingError(
const local_discovery::PrivetLocalPrintOperation* print_operation,
int http_code) {
base::FundamentalValue http_code_value(http_code);
web_ui()->CallJavascriptFunction("onPrivetPrintFailed", http_code_value);
}
void PrintPreviewHandler::FillPrinterDescription(
const std::string& name,
const local_discovery::DeviceDescription& description,

@ -42,6 +42,7 @@ class PrintPreviewHandler
#if defined(ENABLE_MDNS)
public local_discovery::PrivetLocalPrinterLister::Delegate,
public local_discovery::PrivetCapabilitiesOperation::Delegate,
public local_discovery::PrivetLocalPrintOperation::Delegate,
#endif
public ui::SelectFileDialog::Listener,
public printing::PrintViewManagerObserver
@ -91,6 +92,20 @@ class PrintPreviewHandler
local_discovery::PrivetCapabilitiesOperation* capabilities_operation,
int http_error,
const base::DictionaryValue* capabilities) OVERRIDE;
// PrivetLocalPrintOperation::Delegate implementation.
virtual void OnPrivetPrintingRequestPDF(
const local_discovery::PrivetLocalPrintOperation*
print_operation) OVERRIDE;
virtual void OnPrivetPrintingRequestPWGRaster(
const local_discovery::PrivetLocalPrintOperation*
print_operation) OVERRIDE;
virtual void OnPrivetPrintingDone(
const local_discovery::PrivetLocalPrintOperation*
print_operation) OVERRIDE;
virtual void OnPrivetPrintingError(
const local_discovery::PrivetLocalPrintOperation* print_operation,
int http_code) OVERRIDE;
#endif // ENABLE_MDNS
private:
@ -237,9 +252,21 @@ class PrintPreviewHandler
#if defined(ENABLE_MDNS)
void StopPrivetPrinterSearch();
void StartPrivetCapabilities(
void PrivetCapabilitiesUpdateClient(
scoped_ptr<local_discovery::PrivetHTTPClient> http_client);
void PrivetLocalPrintUpdateClient(
std::string printTicket,
scoped_ptr<local_discovery::PrivetHTTPClient> http_client);
bool PrivetUpdateClient(
scoped_ptr<local_discovery::PrivetHTTPClient> http_client);
void StartPrivetLocalPrint(const std::string& print_ticket);
void SendPrivetCapabilitiesError(const std::string& id);
void PrintToPrivetPrinter(const std::string& printer_name,
const std::string& print_ticket);
bool CreatePrivetHTTP(
const std::string& name,
const local_discovery::PrivetHTTPAsynchronousFactory::ResultCallback&
callback);
void FillPrinterDescription(
const std::string& name,
const local_discovery::DeviceDescription& description,
@ -289,6 +316,8 @@ class PrintPreviewHandler
scoped_ptr<local_discovery::PrivetHTTPClient> privet_http_client_;
scoped_ptr<local_discovery::PrivetCapabilitiesOperation>
privet_capabilities_operation_;
scoped_ptr<local_discovery::PrivetLocalPrintOperation>
privet_local_print_operation_;
#endif
base::WeakPtrFactory<PrintPreviewHandler> weak_factory_;

@ -320,6 +320,8 @@ content::WebUIDataSource* CreatePrintPreviewUISource() {
source->AddLocalizedString(
"noDestsPromoNotNowButtonLabel",
IDS_PRINT_PREVIEW_NO_DESTS_PROMO_NOT_NOW_BUTTON_LABEL);
source->AddLocalizedString("couldNotPrint",
IDS_PRINT_PREVIEW_COULD_NOT_PRINT);
source->SetJsonPath("strings.js");
source->AddResourcePath("print_preview.js", IDR_PRINT_PREVIEW_JS);

@ -23,7 +23,7 @@ const int kLocalPrintJobExpirationSec = 20;
const int kErrorTimeoutSec = 30;
// Errors simulation constants:
const double kPaperJamProbability = 0.2;
const double kPaperJamProbability = 1.0;
const int kTooManyDraftsTimeout = 10;
const size_t kMaxDrafts = 5;
@ -321,4 +321,3 @@ void PrintJobHandler::ForgetDraft(const std::string& id) {
void PrintJobHandler::ForgetLocalJob(const std::string& id) {
jobs.erase(id);
}

@ -119,6 +119,13 @@ const char kSettingPrinterName[] = "printerName";
// Print to PDF option: true if selected, false if not.
const char kSettingPrintToPDF[] = "printToPDF";
// Print using Privet option: true if destination is a Privet printer, false if
// not.
const char kSettingPrintWithPrivet[] = "printWithPrivet";
// Ticket option. Contains the ticket in CJT format.
const char kSettingTicket[] = "ticket";
// Whether to print CSS backgrounds.
const char kSettingShouldPrintBackgrounds[] = "shouldPrintBackgrounds";

@ -48,6 +48,8 @@ PRINTING_EXPORT extern const char kSettingPrintableAreaWidth[];
PRINTING_EXPORT extern const char kSettingPrintableAreaHeight[];
PRINTING_EXPORT extern const char kSettingPrinterName[];
PRINTING_EXPORT extern const char kSettingPrintToPDF[];
PRINTING_EXPORT extern const char kSettingPrintWithPrivet[];
PRINTING_EXPORT extern const char kSettingTicket[];
PRINTING_EXPORT extern const char kSettingShouldPrintBackgrounds[];
PRINTING_EXPORT extern const char kSettingShouldPrintSelectionOnly[];