Skip to content

Commit

Permalink
Print to Privet local printers
Browse files Browse the repository at this point in the history
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
  • Loading branch information
noamsml@chromium.org committed Nov 9, 2013
1 parent 901cf6f commit 014a62c
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 33 deletions.
3 changes: 3 additions & 0 deletions chrome/app/generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -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.">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
29 changes: 24 additions & 5 deletions chrome/browser/resources/print_preview/native_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

/**
Expand Down Expand Up @@ -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'
};

/**
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -300,6 +303,10 @@ cr.define('print_preview', function() {
};
}

if (destination.isPrivet) {
ticket['ticket'] = printTicketStore.createPrintTicket(destination);
}

if (opt_isOpenPdfInPreview) {
ticket['OpenPDFInPreview'] = true;
}
Expand Down Expand Up @@ -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);
},

Expand All @@ -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);
}
};

Expand Down
18 changes: 18 additions & 0 deletions chrome/browser/resources/print_preview/print_preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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.
Expand Down
171 changes: 149 additions & 22 deletions chrome/browser/ui/webui/print_preview/print_preview_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -88,6 +91,7 @@ enum UserActionBuckets {
INITIATOR_CRASHED, // UNUSED
INITIATOR_CLOSED,
PRINT_WITH_CLOUD_PRINT,
PRINT_WITH_PRIVET,
USERACTION_BUCKET_BOUNDARY
};

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
Expand All @@ -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);
}

Expand All @@ -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)) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 014a62c

Please sign in to comment.