If you’ve worked with Google Cloud Printing then you know that much of the sample code out there that shows how to submit print jobs using Java or C# don’t work … frustrating to say the least.
After more pain then I’d care to admit, I finally got the code working so wanted to share it.
Below is the code to submit a PDF file for Printing (or storage on a Google Drive) using Google Cloud Printing from an Android device.
For a complete Android Studio project that shows how to interrogate the available printers, get the list of print jobs, and submit a print job download this project zip file.
public class GoogleCloudPrint {
private static final String SERVICE_SOURCE_NAME = "your-apps-name-for-logging-purposes";
public static final String GCP_BASE_URL_STRING =
"https://www.google.com/cloudprint";
private static final String SUBMIT_URL_STRING =
GCP_BASE_URL_STRING + "/submit";
private static final int DEFAULT_STREAMING_CHUNK_SIZE = 0;
String mUsername;
String mPassword;
public GoogleCloudPrint(String username, String password) {
mUsername = username;
mPassword = password;
}
public void print(String printerId, String title, File documentFile, String mimeType) {
try {
byte[] documentBytes = getBytes(documentFile);
String urlString = SUBMIT_URL_STRING +
"?output=json" +
"&printerid=" + printerId +
"&contentType=" + mimeType +
"&title=" + title ;
// Open connection and configure for POST with streaming writes
HttpsURLConnection connection = createConnection(urlString);
connection.setDoOutput(true);
connection.setChunkedStreamingMode(DEFAULT_STREAMING_CHUNK_SIZE);
// Create the multi-part form data prefix and suffix
// include filename value in prefix
String queryPrefix = String.format(
"------CloudPrintFormBoundaryqeq6g6ncj5v7\r\n" +
"Content-Disposition: form-data; name=\"content\"; filename=\"%s\"\r\n" +
"\r\n", title);
String querySuffix = "\r\n------CloudPrintFormBoundaryqeq6g6ncj5v7--";
// Encoide prefix and suffix and determine total content length
byte[] queryPrefixBytes = EncodingUtils.getAsciiBytes(queryPrefix);
byte[] querySuffixBytes = EncodingUtils.getAsciiBytes(querySuffix);
int contentLength = queryPrefixBytes.length + documentBytes.length + querySuffixBytes.length;
// Add headers for multipart form data and length
connection.addRequestProperty("Content-Type",
"multipart/form-data; boundary=----CloudPrintFormBoundaryqeq6g6ncj5v7");
connection.addRequestProperty("Content-Length", Integer.toString(contentLength));
// Write the document to server wrapped as multipart form data
writePrintBody(connection, queryPrefixBytes, documentBytes, querySuffixBytes);
// Write results to log
InputStream inStream = connection.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
}
private HttpsURLConnection createConnection(String urlString) throws IOException {
String auth = retrieveAuthToken(mUsername, mPassword);
URL url = new URL(urlString);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.addRequestProperty("X-CloudPrint-Proxy", SERVICE_SOURCE_NAME);
connection.addRequestProperty("Authorization", "GoogleLogin auth=" + auth);
return connection;
}
private void writePrintBody(HttpsURLConnection connection, byte[] prefixBytes,
byte[] documentByes, byte[] suffixBytes) throws IOException {
OutputStream outStream = new BufferedOutputStream(connection.getOutputStream());
outStream.write(prefixBytes, 0, prefixBytes.length);
outStream.write(documentByes, 0, documentByes.length);
outStream.write(suffixBytes, 0, suffixBytes.length);
outStream.flush();
outStream.close();
}
private String retrieveAuthToken(String userId, String password) {
final String AUTHORIZE_URL_FORMAT = "https://www.google.com/accounts/ClientLogin" +
"?accountType=HOSTED_OR_GOOGLE" +
"&Email=%s" +
"&Passwd=%s" +
"&service=cloudprint" +
"&source=" + SERVICE_SOURCE_NAME;
String authorizeURL = String.format(AUTHORIZE_URL_FORMAT, userId, password);
String auth = "NOT_SET";
InputStream inStream = null;
BufferedReader reader = null;
try {
URL url = new URL(authorizeURL);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
inStream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(inStream));
String buffer;
StringBuilder stringBuilder = new StringBuilder();
while ((buffer = reader.readLine()) != null) {
String[] parts = buffer.split("=");
if ("Auth".equalsIgnoreCase(parts[0])) {
auth = parts[1];
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (reader != null)
reader.close();
if (inStream != null)
inStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return auth;
}
private byte[] getBytes(File documentFile) {
byte[] bytes = null;
try {
FileInputStream inputStream = new FileInputStream(documentFile);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = inputStream.read(buffer);
while (n >= 0) {
baos.write(buffer, 0, n);
n = inputStream.read(buffer);
}
inputStream.close();
baos.flush();
bytes = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return bytes;
}
}
