| /* |
| * 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; |
| } |
| } |
| } |