blob: 0546a43166197174c3f30ec07ffeb4b05beb8f8c [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.printspooler;
import android.content.ComponentName;
import android.content.Context;
import android.os.AsyncTask;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.IPrintClient;
import android.print.IPrintSpoolerClient;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.print.PrintDocumentInfo;
import android.print.PrinterId;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PrintSpooler {
private static final String LOG_TAG = PrintSpooler.class.getSimpleName();
private static final boolean DEBUG_PRINT_JOB_LIFECYCLE = false;
private static final boolean DEBUG_PERSISTENCE = false;
private static final boolean PERSISTNECE_MANAGER_ENABLED = false;
private static final String PRINT_FILE_EXTENSION = "pdf";
private static int sPrintJobIdCounter;
private static final Object sLock = new Object();
private static PrintSpooler sInstance;
private final Object mLock = new Object();
private final List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>();
private final PersistenceManager mPersistanceManager;
private final Context mContext;
public IPrintSpoolerClient mClient;
public static PrintSpooler getInstance(Context context) {
synchronized (sLock) {
if (sInstance == null) {
sInstance = new PrintSpooler(context);
}
return sInstance;
}
}
private PrintSpooler(Context context) {
mContext = context;
mPersistanceManager = new PersistenceManager();
mPersistanceManager.readStateLocked();
}
public void setCleint(IPrintSpoolerClient client) {
synchronized (mLock) {
mClient = client;
}
}
public void startPrinterDiscovery(IPrinterDiscoveryObserver observer) {
IPrintSpoolerClient client = null;
synchronized (mLock) {
client = mClient;
}
if (client != null) {
try {
client.onStartPrinterDiscovery(observer);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error notifying start printer discovery.", re);
}
}
}
public void stopPrinterDiscovery() {
IPrintSpoolerClient client = null;
synchronized (mLock) {
client = mClient;
}
if (client != null) {
try {
client.onStopPrinterDiscovery();
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error notifying stop printer discovery.", re);
}
}
}
public List<PrintJobInfo> getPrintJobs(ComponentName componentName, int state, int appId) {
synchronized (mLock) {
List<PrintJobInfo> foundPrintJobs = null;
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
PrinterId printerId = printJob.getPrinterId();
final boolean sameComponent = (componentName == null
|| (printerId != null
&& componentName.equals(printerId.getService())));
final boolean sameAppId = appId == PrintManager.APP_ID_ANY
|| printJob.getAppId() == appId;
final boolean sameState = state == PrintJobInfo.STATE_ANY
|| state == printJob.getState();
if (sameComponent && sameAppId && sameState) {
if (foundPrintJobs == null) {
foundPrintJobs = new ArrayList<PrintJobInfo>();
}
foundPrintJobs.add(printJob);
}
}
return foundPrintJobs;
}
}
public PrintJobInfo getPrintJob(int printJobId, int appId) {
synchronized (mLock) {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
if (printJob.getId() == printJobId
&& (appId == PrintManager.APP_ID_ANY || appId == printJob.getAppId())) {
return printJob;
}
}
return null;
}
}
public boolean cancelPrintJob(int printJobId, int appId) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJob(printJobId, appId);
if (printJob != null) {
switch (printJob.getState()) {
case PrintJobInfo.STATE_CREATED:
case PrintJobInfo.STATE_QUEUED: {
setPrintJobState(printJobId, PrintJobInfo.STATE_CANCELED);
} return true;
}
}
return false;
}
}
public PrintJobInfo createPrintJob(CharSequence label, IPrintClient client,
PrintAttributes attributes, int appId) {
synchronized (mLock) {
final int printJobId = generatePrintJobIdLocked();
PrintJobInfo printJob = new PrintJobInfo();
printJob.setId(printJobId);
printJob.setAppId(appId);
printJob.setLabel(label);
printJob.setAttributes(attributes);
addPrintJobLocked(printJob);
setPrintJobState(printJobId, PrintJobInfo.STATE_CREATED);
return printJob;
}
}
public void notifyClientForActivteJobs() {
IPrintSpoolerClient client = null;
Map<ComponentName, List<PrintJobInfo>> activeJobsPerServiceMap =
new HashMap<ComponentName, List<PrintJobInfo>>();
synchronized(mLock) {
if (mClient == null) {
throw new IllegalStateException("Client cannot be null.");
}
client = mClient;
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
switch (printJob.getState()) {
case PrintJobInfo.STATE_CREATED: {
/* skip - not ready to be handled by a service */
} break;
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
ComponentName service = printJob.getPrinterId().getService();
List<PrintJobInfo> jobsPerService = activeJobsPerServiceMap.get(service);
if (jobsPerService == null) {
jobsPerService = new ArrayList<PrintJobInfo>();
activeJobsPerServiceMap.put(service, jobsPerService);
}
jobsPerService.add(printJob);
} break;
default: {
ComponentName service = printJob.getPrinterId().getService();
if (!activeJobsPerServiceMap.containsKey(service)) {
activeJobsPerServiceMap.put(service, null);
}
}
}
}
}
boolean allPrintJobsHandled = true;
for (Map.Entry<ComponentName, List<PrintJobInfo>> entry
: activeJobsPerServiceMap.entrySet()) {
ComponentName service = entry.getKey();
List<PrintJobInfo> printJobs = entry.getValue();
if (printJobs != null) {
allPrintJobsHandled = false;
final int printJobCount = printJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = printJobs.get(i);
if (printJob.getState() == PrintJobInfo.STATE_QUEUED) {
callOnPrintJobQueuedQuietly(client, printJob);
}
}
} else {
callOnAllPrintJobsForServiceHandledQuietly(client, service);
}
}
if (allPrintJobsHandled) {
callOnAllPrintJobsHandledQuietly(client);
}
}
private int generatePrintJobIdLocked() {
int printJobId = sPrintJobIdCounter++;
while (isDuplicatePrintJobId(printJobId)) {
printJobId = sPrintJobIdCounter++;
}
return printJobId;
}
private boolean isDuplicatePrintJobId(int printJobId) {
final int printJobCount = mPrintJobs.size();
for (int j = 0; j < printJobCount; j++) {
PrintJobInfo printJob = mPrintJobs.get(j);
if (printJob.getId() == printJobId) {
return true;
}
}
return false;
}
@SuppressWarnings("resource")
public boolean writePrintJobData(ParcelFileDescriptor fd, int printJobId) {
synchronized (mLock) {
FileInputStream in = null;
FileOutputStream out = null;
try {
PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
File file = generateFileForPrintJob(printJobId);
in = new FileInputStream(file);
out = new FileOutputStream(fd.getFileDescriptor());
final byte[] buffer = new byte[8192];
while (true) {
final int readByteCount = in.read(buffer);
if (readByteCount < 0) {
return true;
}
out.write(buffer, 0, readByteCount);
}
}
} catch (FileNotFoundException fnfe) {
Log.e(LOG_TAG, "Error writing print job data!", fnfe);
} catch (IOException ioe) {
Log.e(LOG_TAG, "Error writing print job data!", ioe);
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(fd);
}
}
return false;
}
public File generateFileForPrintJob(int printJobId) {
return new File(mContext.getFilesDir(), "print_job_"
+ printJobId + "." + PRINT_FILE_EXTENSION);
}
private void addPrintJobLocked(PrintJobInfo printJob) {
mPrintJobs.add(printJob);
if (DEBUG_PRINT_JOB_LIFECYCLE) {
Slog.i(LOG_TAG, "[ADD] " + printJob);
}
}
private void removePrintJobLocked(PrintJobInfo printJob) {
if (mPrintJobs.remove(printJob)) {
generateFileForPrintJob(printJob.getId()).delete();
if (DEBUG_PRINT_JOB_LIFECYCLE) {
Slog.i(LOG_TAG, "[REMOVE] " + printJob);
}
}
}
public boolean setPrintJobState(int printJobId, int state) {
boolean success = false;
boolean allPrintJobsHandled = false;
boolean allPrintJobsForServiceHandled = false;
IPrintSpoolerClient client = null;
PrintJobInfo queuedPrintJob = null;
PrintJobInfo removedPrintJob = null;
synchronized (mLock) {
if (mClient == null) {
throw new IllegalStateException("Client cannot be null.");
}
client = mClient;
PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null && printJob.getState() < state) {
success = true;
printJob.setState(state);
// TODO: Update notifications.
switch (state) {
case PrintJobInfo.STATE_COMPLETED:
case PrintJobInfo.STATE_CANCELED: {
removedPrintJob = printJob;
removePrintJobLocked(printJob);
// No printer means creation of a print job was cancelled,
// therefore the state of the spooler did not change and no
// notifications are needed. We also do not need to persist
// the state.
PrinterId printerId = printJob.getPrinterId();
if (printerId == null) {
return true;
}
allPrintJobsHandled = !hasActivePrintJobsLocked();
allPrintJobsForServiceHandled = !hasActivePrintJobsForServiceLocked(
printerId.getService());
} break;
case PrintJobInfo.STATE_QUEUED: {
queuedPrintJob = new PrintJobInfo(printJob);
} break;
}
if (DEBUG_PRINT_JOB_LIFECYCLE) {
Slog.i(LOG_TAG, "[STATUS CHANGED] " + printJob);
}
mPersistanceManager.writeStateLocked();
}
}
if (queuedPrintJob != null) {
callOnPrintJobQueuedQuietly(client, queuedPrintJob);
}
if (allPrintJobsForServiceHandled) {
callOnAllPrintJobsForServiceHandledQuietly(client,
removedPrintJob.getPrinterId().getService());
}
if (allPrintJobsHandled) {
callOnAllPrintJobsHandledQuietly(client);
}
return success;
}
private void callOnPrintJobQueuedQuietly(IPrintSpoolerClient client,
PrintJobInfo printJob) {
try {
client.onPrintJobQueued(printJob);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error notify for a queued print job.", re);
}
}
private void callOnAllPrintJobsForServiceHandledQuietly(IPrintSpoolerClient client,
ComponentName service) {
try {
client.onAllPrintJobsForServiceHandled(service);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error notify for all print jobs per service handled.", re);
}
}
private void callOnAllPrintJobsHandledQuietly(IPrintSpoolerClient client) {
try {
client.onAllPrintJobsHandled();
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error notify for all print job handled.", re);
}
}
private boolean hasActivePrintJobsLocked() {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
return true;
}
}
}
return false;
}
private boolean hasActivePrintJobsForServiceLocked(ComponentName service) {
final int printJobCount = mPrintJobs.size();
for (int i = 0; i < printJobCount; i++) {
PrintJobInfo printJob = mPrintJobs.get(i);
switch (printJob.getState()) {
case PrintJobInfo.STATE_QUEUED:
case PrintJobInfo.STATE_STARTED: {
if (printJob.getPrinterId().getService().equals(service)) {
return true;
}
} break;
}
}
return false;
}
public boolean setPrintJobTag(int printJobId, String tag) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setTag(tag);
mPersistanceManager.writeStateLocked();
return true;
}
}
return false;
}
public final boolean setPrintJobPrintDocumentInfo(int printJobId, PrintDocumentInfo info) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setDocumentInfo(info);
mPersistanceManager.writeStateLocked();
return true;
}
}
return false;
}
public void setPrintJobAttributes(int printJobId, PrintAttributes attributes) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setAttributes(attributes);
mPersistanceManager.writeStateLocked();
}
}
}
public void setPrintJobPrinterId(int printJobId, PrinterId printerId) {
synchronized (mLock) {
PrintJobInfo printJob = getPrintJob(printJobId, PrintManager.APP_ID_ANY);
if (printJob != null) {
printJob.setPrinterId(printerId);
mPersistanceManager.writeStateLocked();
}
}
}
private final class PersistenceManager {
private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
private static final String TAG_SPOOLER = "spooler";
private static final String TAG_JOB = "job";
private static final String TAG_ID = "id";
private static final String TAG_TAG = "tag";
private static final String TAG_APP_ID = "app-id";
private static final String TAG_STATE = "state";
private static final String TAG_ATTRIBUTES = "attributes";
private static final String TAG_LABEL = "label";
private static final String TAG_PRINTER = "printer";
private static final String ATTRIBUTE_MEDIA_SIZE = "mediaSize";
private static final String ATTRIBUTE_RESOLUTION = "resolution";
private static final String ATTRIBUTE_MARGINS = "margins";
private static final String ATTRIBUTE_INPUT_TRAY = "inputTray";
private static final String ATTRIBUTE_OUTPUT_TRAY = "outputTray";
private static final String ATTRIBUTE_DUPLEX_MODE = "duplexMode";
private static final String ATTRIBUTE_COLOR_MODE = "colorMode";
private static final String ATTRIBUTE_FITTING_MODE = "fittingMode";
private static final String ATTRIBUTE_ORIENTATION = "orientation";
private final AtomicFile mStatePersistFile;
private boolean mWriteStateScheduled;
private PersistenceManager() {
mStatePersistFile = new AtomicFile(new File(mContext.getFilesDir(),
PERSIST_FILE_NAME));
}
public void writeStateLocked() {
// TODO: Implement persistence of PrintableInfo
if (!PERSISTNECE_MANAGER_ENABLED) {
return;
}
if (mWriteStateScheduled) {
return;
}
mWriteStateScheduled = true;
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
synchronized (mLock) {
mWriteStateScheduled = false;
doWriteStateLocked();
}
return null;
}
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
private void doWriteStateLocked() {
FileOutputStream out = null;
try {
out = mStatePersistFile.startWrite();
XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(out, "utf-8");
serializer.startDocument(null, true);
serializer.startTag(null, TAG_SPOOLER);
List<PrintJobInfo> printJobs = mPrintJobs;
final int printJobCount = printJobs.size();
for (int j = 0; j < printJobCount; j++) {
PrintJobInfo printJob = printJobs.get(j);
final int state = printJob.getState();
if (state < PrintJobInfo.STATE_QUEUED
|| state > PrintJobInfo.STATE_FAILED) {
continue;
}
serializer.startTag(null, TAG_JOB);
serializer.startTag(null, TAG_ID);
serializer.text(String.valueOf(printJob.getId()));
serializer.endTag(null, TAG_ID);
serializer.startTag(null, TAG_TAG);
serializer.text(printJob.getTag());
serializer.endTag(null, TAG_TAG);
serializer.startTag(null, TAG_APP_ID);
serializer.text(String.valueOf(printJob.getAppId()));
serializer.endTag(null, TAG_APP_ID);
serializer.startTag(null, TAG_LABEL);
serializer.text(printJob.getLabel().toString());
serializer.endTag(null, TAG_LABEL);
serializer.startTag(null, TAG_STATE);
serializer.text(String.valueOf(printJob.getState()));
serializer.endTag(null, TAG_STATE);
serializer.startTag(null, TAG_PRINTER);
serializer.text(printJob.getPrinterId().flattenToString());
serializer.endTag(null, TAG_PRINTER);
PrintAttributes attributes = printJob.getAttributes();
if (attributes != null) {
serializer.startTag(null, TAG_ATTRIBUTES);
//TODO: Implement persistence of the attributes below.
// MediaSize mediaSize = attributes.getMediaSize();
// if (mediaSize != null) {
// serializer.attribute(null, ATTRIBUTE_MEDIA_SIZE,
// mediaSize.flattenToString());
// }
//
// Resolution resolution = attributes.getResolution();
// if (resolution != null) {
// serializer.attribute(null, ATTRIBUTE_RESOLUTION,
// resolution.flattenToString());
// }
//
// Margins margins = attributes.getMargins();
// if (margins != null) {
// serializer.attribute(null, ATTRIBUTE_MARGINS,
// margins.flattenToString());
// }
//
// Tray inputTray = attributes.getInputTray();
// if (inputTray != null) {
// serializer.attribute(null, ATTRIBUTE_INPUT_TRAY,
// inputTray.flattenToString());
// }
//
// Tray outputTray = attributes.getOutputTray();
// if (outputTray != null) {
// serializer.attribute(null, ATTRIBUTE_OUTPUT_TRAY,
// outputTray.flattenToString());
// }
final int duplexMode = attributes.getDuplexMode();
if (duplexMode > 0) {
serializer.attribute(null, ATTRIBUTE_DUPLEX_MODE,
String.valueOf(duplexMode));
}
final int colorMode = attributes.getColorMode();
if (colorMode > 0) {
serializer.attribute(null, ATTRIBUTE_COLOR_MODE,
String.valueOf(colorMode));
}
final int fittingMode = attributes.getFittingMode();
if (fittingMode > 0) {
serializer.attribute(null, ATTRIBUTE_FITTING_MODE,
String.valueOf(fittingMode));
}
final int orientation = attributes.getOrientation();
if (orientation > 0) {
serializer.attribute(null, ATTRIBUTE_ORIENTATION,
String.valueOf(orientation));
}
serializer.endTag(null, TAG_ATTRIBUTES);
}
serializer.endTag(null, TAG_JOB);
if (DEBUG_PERSISTENCE) {
Log.i(LOG_TAG, "[PERSISTED] " + printJob);
}
}
serializer.endTag(null, TAG_SPOOLER);
serializer.endDocument();
mStatePersistFile.finishWrite(out);
} catch (IOException e) {
Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e);
mStatePersistFile.failWrite(out);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ioe) {
/* ignore */
}
}
}
}
public void readStateLocked() {
if (!PERSISTNECE_MANAGER_ENABLED) {
return;
}
FileInputStream in = null;
try {
in = mStatePersistFile.openRead();
} catch (FileNotFoundException e) {
Log.i(LOG_TAG, "No existing print spooler state.");
return;
}
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, null);
parseState(parser);
} catch (IllegalStateException ise) {
Slog.w(LOG_TAG, "Failed parsing " + ise);
} catch (NullPointerException npe) {
Slog.w(LOG_TAG, "Failed parsing " + npe);
} catch (NumberFormatException nfe) {
Slog.w(LOG_TAG, "Failed parsing " + nfe);
} catch (XmlPullParserException xppe) {
Slog.w(LOG_TAG, "Failed parsing " + xppe);
} catch (IOException ioe) {
Slog.w(LOG_TAG, "Failed parsing " + ioe);
} catch (IndexOutOfBoundsException iobe) {
Slog.w(LOG_TAG, "Failed parsing " + iobe);
} finally {
try {
in.close();
} catch (IOException ioe) {
/* ignore */
}
}
}
private void parseState(XmlPullParser parser)
throws IOException, XmlPullParserException {
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_SPOOLER);
parser.next();
while (parsePrintJob(parser)) {
parser.next();
}
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_SPOOLER);
}
private boolean parsePrintJob(XmlPullParser parser)
throws IOException, XmlPullParserException {
skipEmptyTextTags(parser);
if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) {
return false;
}
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_ID);
parser.next();
final int printJobId = Integer.parseInt(parser.getText());
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_ID);
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_TAG);
parser.next();
String tag = parser.getText();
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_TAG);
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_APP_ID);
parser.next();
final int appId = Integer.parseInt(parser.getText());
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_APP_ID);
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_LABEL);
parser.next();
String label = parser.getText();
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_LABEL);
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_STATE);
parser.next();
final int state = Integer.parseInt(parser.getText());
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_STATE);
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_PRINTER);
parser.next();
PrinterId printerId = PrinterId.unflattenFromString(parser.getText());
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_PRINTER);
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES);
final int attributeCount = parser.getAttributeCount();
PrintAttributes attributes = null;
if (attributeCount > 0) {
PrintAttributes.Builder builder = new PrintAttributes.Builder();
// TODO: Implement reading of the attributes below.
// String mediaSize = parser.getAttributeValue(null, ATTRIBUTE_MEDIA_SIZE);
// if (mediaSize != null) {
// builder.setMediaSize(MediaSize.unflattenFromString(mediaSize));
// }
//
// String resolution = parser.getAttributeValue(null, ATTRIBUTE_RESOLUTION);
// if (resolution != null) {
// builder.setMediaSize(Resolution.unflattenFromString(resolution));
// }
//
// String margins = parser.getAttributeValue(null, ATTRIBUTE_MARGINS);
// if (margins != null) {
// builder.setMediaSize(Margins.unflattenFromString(margins));
// }
//
// String inputTray = parser.getAttributeValue(null, ATTRIBUTE_INPUT_TRAY);
// if (inputTray != null) {
// builder.setMediaSize(Tray.unflattenFromString(inputTray));
// }
//
// String outputTray = parser.getAttributeValue(null, ATTRIBUTE_OUTPUT_TRAY);
// if (outputTray != null) {
// builder.setMediaSize(Tray.unflattenFromString(outputTray));
// }
//
// String duplexMode = parser.getAttributeValue(null, ATTRIBUTE_DUPLEX_MODE);
// if (duplexMode != null) {
// builder.setDuplexMode(Integer.parseInt(duplexMode));
// }
String colorMode = parser.getAttributeValue(null, ATTRIBUTE_COLOR_MODE);
if (colorMode != null) {
builder.setColorMode(Integer.parseInt(colorMode));
}
String fittingMode = parser.getAttributeValue(null, ATTRIBUTE_COLOR_MODE);
if (fittingMode != null) {
builder.setFittingMode(Integer.parseInt(fittingMode));
}
}
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
parser.next();
PrintJobInfo printJob = new PrintJobInfo();
printJob.setId(printJobId);
printJob.setTag(tag);
printJob.setAppId(appId);
printJob.setLabel(label);
printJob.setState(state);
printJob.setAttributes(attributes);
printJob.setPrinterId(printerId);
mPrintJobs.add(printJob);
if (DEBUG_PERSISTENCE) {
Log.i(LOG_TAG, "[RESTORED] " + printJob);
}
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.END_TAG, TAG_JOB);
return true;
}
private void expect(XmlPullParser parser, int type, String tag)
throws IOException, XmlPullParserException {
if (!accept(parser, type, tag)) {
throw new XmlPullParserException("Exepected event: " + type
+ " and tag: " + tag + " but got event: " + parser.getEventType()
+ " and tag:" + parser.getName());
}
}
private void skipEmptyTextTags(XmlPullParser parser)
throws IOException, XmlPullParserException {
while (accept(parser, XmlPullParser.TEXT, null)
&& "\n".equals(parser.getText())) {
parser.next();
}
}
private boolean accept(XmlPullParser parser, int type, String tag)
throws IOException, XmlPullParserException {
if (parser.getEventType() != type) {
return false;
}
if (tag != null) {
if (!tag.equals(parser.getName())) {
return false;
}
} else if (parser.getName() != null) {
return false;
}
return true;
}
}
}