@Override
  protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    synchronized (mLock) {
      String prefix = (args.length > 0) ? args[0] : "";
      String tab = "  ";

      pw.append(prefix).append("print jobs:").println();
      final int printJobCount = mPrintJobs.size();
      for (int i = 0; i < printJobCount; i++) {
        PrintJobInfo printJob = mPrintJobs.get(i);
        pw.append(prefix).append(tab).append(printJob.toString());
        pw.println();
      }

      pw.append(prefix).append("print job files:").println();
      File[] files = getFilesDir().listFiles();
      if (files != null) {
        final int fileCount = files.length;
        for (int i = 0; i < fileCount; i++) {
          File file = files[i];
          if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
            pw.append(prefix).append(tab).append(file.getName()).println();
          }
        }
      }
    }
  }
 public boolean hasActivePrintJobsLocked() {
   final int printJobCount = mPrintJobs.size();
   for (int i = 0; i < printJobCount; i++) {
     PrintJobInfo printJob = mPrintJobs.get(i);
     if (isActiveState(printJob.getState())) {
       return true;
     }
   }
   return false;
 }
 public boolean hasActivePrintJobsForServiceLocked(ComponentName service) {
   final int printJobCount = mPrintJobs.size();
   for (int i = 0; i < printJobCount; i++) {
     PrintJobInfo printJob = mPrintJobs.get(i);
     if (isActiveState(printJob.getState())
         && printJob.getPrinterId() != null
         && printJob.getPrinterId().getServiceName().equals(service)) {
       return true;
     }
   }
   return false;
 }
 public PrintJobInfo getPrintJobInfo(PrintJobId 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().equals(printJobId)
           && (appId == PrintManager.APP_ID_ANY || appId == printJob.getAppId())) {
         return printJob;
       }
     }
     return null;
   }
 }
    /**
     * Puts an advanced (printer specific) option.
     *
     * @param key The option key.
     * @param value The option value.
     */
    public void putAdvancedOption(@NonNull String key, @Nullable String value) {
      Preconditions.checkNotNull(key, "key cannot be null");

      if (mPrototype.mAdvancedOptions == null) {
        mPrototype.mAdvancedOptions = new Bundle();
      }
      mPrototype.mAdvancedOptions.putString(key, value);
    }
  public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
    synchronized (mLock) {
      PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
      if (printJob != null) {
        printJob.setCancelling(cancelling);
        if (shouldPersistPrintJob(printJob)) {
          mPersistanceManager.writeStateLocked();
        }
        mNotificationController.onUpdateNotifications(mPrintJobs);

        Message message =
            mHandlerCaller.obtainMessageO(
                HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED, printJob);
        mHandlerCaller.executeOrSendMessage(message);
      }
    }
  }
 public List<PrintJobInfo> getPrintJobInfos(ComponentName componentName, int state, int appId) {
   List<PrintJobInfo> foundPrintJobs = null;
   synchronized (mLock) {
     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.getServiceName())));
       final boolean sameAppId = appId == PrintManager.APP_ID_ANY || printJob.getAppId() == appId;
       final boolean sameState =
           (state == printJob.getState())
               || (state == PrintJobInfo.STATE_ANY)
               || (state == PrintJobInfo.STATE_ANY_VISIBLE_TO_CLIENTS
                   && isStateVisibleToUser(printJob.getState()))
               || (state == PrintJobInfo.STATE_ANY_ACTIVE && isActiveState(printJob.getState()))
               || (state == PrintJobInfo.STATE_ANY_SCHEDULED
                   && isScheduledState(printJob.getState()));
       if (sameComponent && sameAppId && sameState) {
         if (foundPrintJobs == null) {
           foundPrintJobs = new ArrayList<>();
         }
         foundPrintJobs.add(printJob);
       }
     }
   }
   return foundPrintJobs;
 }
  public void createPrintJob(PrintJobInfo printJob) {
    synchronized (mLock) {
      addPrintJobLocked(printJob);
      setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null);

      Message message =
          mHandlerCaller.obtainMessageO(
              HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED, printJob);
      mHandlerCaller.executeOrSendMessage(message);
    }
  }
 private void removeObsoletePrintJobs() {
   synchronized (mLock) {
     boolean persistState = false;
     final int printJobCount = mPrintJobs.size();
     for (int i = printJobCount - 1; i >= 0; i--) {
       PrintJobInfo printJob = mPrintJobs.get(i);
       if (isObsoleteState(printJob.getState())) {
         mPrintJobs.remove(i);
         if (DEBUG_PRINT_JOB_LIFECYCLE) {
           Slog.i(LOG_TAG, "[REMOVE] " + printJob.getId().flattenToString());
         }
         removePrintJobFileLocked(printJob.getId());
         persistState = true;
       }
     }
     if (persistState) {
       mPersistanceManager.writeStateLocked();
     }
   }
 }
 public boolean setPrintJobTag(PrintJobId printJobId, String tag) {
   synchronized (mLock) {
     PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
     if (printJob != null) {
       String printJobTag = printJob.getTag();
       if (printJobTag == null) {
         if (tag == null) {
           return false;
         }
       } else if (printJobTag.equals(tag)) {
         return false;
       }
       printJob.setTag(tag);
       if (shouldPersistPrintJob(printJob)) {
         mPersistanceManager.writeStateLocked();
       }
       return true;
     }
   }
   return false;
 }
 /**
  * Should the print job the shown to the user in the settings app.
  *
  * @param printJob The print job in question.
  * @return true iff the print job should be shown.
  */
 private static boolean shouldShowToUser(PrintJobInfo printJob) {
   switch (printJob.getState()) {
     case PrintJobInfo.STATE_QUEUED:
     case PrintJobInfo.STATE_STARTED:
     case PrintJobInfo.STATE_BLOCKED:
     case PrintJobInfo.STATE_FAILED:
       {
         return true;
       }
   }
   return false;
 }
 private boolean shouldPersistPrintJob(PrintJobInfo printJob) {
   return printJob.getState() >= PrintJobInfo.STATE_QUEUED;
 }
 public void updatePrintJobUserConfigurableOptionsNoPersistence(PrintJobInfo printJob) {
   synchronized (mLock) {
     final int printJobCount = mPrintJobs.size();
     for (int i = 0; i < printJobCount; i++) {
       PrintJobInfo cachedPrintJob = mPrintJobs.get(i);
       if (cachedPrintJob.getId().equals(printJob.getId())) {
         cachedPrintJob.setPrinterId(printJob.getPrinterId());
         cachedPrintJob.setPrinterName(printJob.getPrinterName());
         cachedPrintJob.setCopies(printJob.getCopies());
         cachedPrintJob.setDocumentInfo(printJob.getDocumentInfo());
         cachedPrintJob.setPages(printJob.getPages());
         cachedPrintJob.setAttributes(printJob.getAttributes());
         cachedPrintJob.setAdvancedOptions(printJob.getAdvancedOptions());
         return;
       }
     }
     throw new IllegalArgumentException("No print job with id:" + printJob.getId());
   }
 }
 /**
  * Sets the included pages.
  *
  * @param pages The included pages.
  */
 public void setPages(@NonNull PageRange[] pages) {
   mPrototype.mPageRanges = pages;
 }
    /**
     * Sets the progress of the print job.
     *
     * @param progress the progress of the job
     * @hide
     */
    public void setProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
      Preconditions.checkArgumentInRange(progress, 0, 1, "progress");

      mPrototype.mProgress = progress;
    }
 /**
  * Sets the status of the print job.
  *
  * @param status the status of the job, can be null
  * @hide
  */
 public void setStatus(@Nullable CharSequence status) {
   mPrototype.mStatus = status;
 }
  public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
    boolean success = false;

    synchronized (mLock) {
      PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
      if (printJob != null) {
        final int oldState = printJob.getState();
        if (oldState == state) {
          return false;
        }

        success = true;

        printJob.setState(state);
        printJob.setStateReason(error);
        printJob.setCancelling(false);

        if (DEBUG_PRINT_JOB_LIFECYCLE) {
          Slog.i(LOG_TAG, "[STATE CHANGED] " + printJob);
        }

        switch (state) {
          case PrintJobInfo.STATE_COMPLETED:
          case PrintJobInfo.STATE_CANCELED:
            mPrintJobs.remove(printJob);
            removePrintJobFileLocked(printJob.getId());
            // $fall-through$

          case PrintJobInfo.STATE_FAILED:
            {
              PrinterId printerId = printJob.getPrinterId();
              if (printerId != null) {
                ComponentName service = printerId.getServiceName();
                if (!hasActivePrintJobsForServiceLocked(service)) {
                  sendOnAllPrintJobsForServiceHandled(service);
                }
              }
            }
            break;

          case PrintJobInfo.STATE_QUEUED:
            {
              sendOnPrintJobQueued(new PrintJobInfo(printJob));
            }
            break;
        }

        if (shouldPersistPrintJob(printJob)) {
          mPersistanceManager.writeStateLocked();
        }

        if (!hasActivePrintJobsLocked()) {
          notifyOnAllPrintJobsHandled();
        }

        Message message =
            mHandlerCaller.obtainMessageO(
                HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED, printJob);
        mHandlerCaller.executeOrSendMessage(message);

        mNotificationController.onUpdateNotifications(mPrintJobs);
      }
    }

    return success;
  }
  private void handleReadPrintJobsLocked() {
    // Make a map with the files for a print job since we may have
    // to delete some. One example of getting orphan files if the
    // spooler crashes while constructing a print job. We do not
    // persist partially populated print jobs under construction to
    // avoid special handling for various attributes missing.
    ArrayMap<PrintJobId, File> fileForJobMap = null;
    File[] files = getFilesDir().listFiles();
    if (files != null) {
      final int fileCount = files.length;
      for (int i = 0; i < fileCount; i++) {
        File file = files[i];
        if (file.isFile() && file.getName().startsWith(PRINT_JOB_FILE_PREFIX)) {
          if (fileForJobMap == null) {
            fileForJobMap = new ArrayMap<PrintJobId, File>();
          }
          String printJobIdString =
              file.getName().substring(PRINT_JOB_FILE_PREFIX.length(), file.getName().indexOf('.'));
          PrintJobId printJobId = PrintJobId.unflattenFromString(printJobIdString);
          fileForJobMap.put(printJobId, file);
        }
      }
    }

    final int printJobCount = mPrintJobs.size();
    for (int i = 0; i < printJobCount; i++) {
      PrintJobInfo printJob = mPrintJobs.get(i);

      // We want to have only the orphan files at the end.
      if (fileForJobMap != null) {
        fileForJobMap.remove(printJob.getId());
      }

      switch (printJob.getState()) {
        case PrintJobInfo.STATE_QUEUED:
        case PrintJobInfo.STATE_STARTED:
        case PrintJobInfo.STATE_BLOCKED:
          {
            // We have a print job that was queued or started or blocked in
            // the past but the device battery died or a crash occurred. In
            // this case we assume the print job failed and let the user
            // decide whether to restart the job or just cancel it.
            setPrintJobState(
                printJob.getId(),
                PrintJobInfo.STATE_FAILED,
                getString(R.string.no_connection_to_printer));
          }
          break;
      }
    }

    if (!mPrintJobs.isEmpty()) {
      // Update the notification.
      mNotificationController.onUpdateNotifications(mPrintJobs);
    }

    // Delete the orphan files.
    if (fileForJobMap != null) {
      final int orphanFileCount = fileForJobMap.size();
      for (int i = 0; i < orphanFileCount; i++) {
        File file = fileForJobMap.valueAt(i);
        file.delete();
      }
    }
  }
 /**
  * Sets the print job attributes.
  *
  * @param attributes The attributes.
  */
 public void setAttributes(@NonNull PrintAttributes attributes) {
   mPrototype.mAttributes = attributes;
 }
    private void doWriteStateLocked() {
      if (DEBUG_PERSISTENCE) {
        Log.i(LOG_TAG, "[PERSIST START]");
      }
      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);

          if (!shouldPersistPrintJob(printJob)) {
            continue;
          }

          serializer.startTag(null, TAG_JOB);

          serializer.attribute(null, ATTR_ID, printJob.getId().flattenToString());
          serializer.attribute(null, ATTR_LABEL, printJob.getLabel().toString());
          serializer.attribute(null, ATTR_STATE, String.valueOf(printJob.getState()));
          serializer.attribute(null, ATTR_APP_ID, String.valueOf(printJob.getAppId()));
          String tag = printJob.getTag();
          if (tag != null) {
            serializer.attribute(null, ATTR_TAG, tag);
          }
          serializer.attribute(
              null, ATTR_CREATION_TIME, String.valueOf(printJob.getCreationTime()));
          serializer.attribute(null, ATTR_COPIES, String.valueOf(printJob.getCopies()));
          String printerName = printJob.getPrinterName();
          if (!TextUtils.isEmpty(printerName)) {
            serializer.attribute(null, ATTR_PRINTER_NAME, printerName);
          }
          String stateReason = printJob.getStateReason();
          if (!TextUtils.isEmpty(stateReason)) {
            serializer.attribute(null, ATTR_STATE_REASON, stateReason);
          }
          serializer.attribute(null, ATTR_CANCELLING, String.valueOf(printJob.isCancelling()));

          PrinterId printerId = printJob.getPrinterId();
          if (printerId != null) {
            serializer.startTag(null, TAG_PRINTER_ID);
            serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
            serializer.attribute(
                null, ATTR_SERVICE_NAME, printerId.getServiceName().flattenToString());
            serializer.endTag(null, TAG_PRINTER_ID);
          }

          PageRange[] pages = printJob.getPages();
          if (pages != null) {
            for (int i = 0; i < pages.length; i++) {
              serializer.startTag(null, TAG_PAGE_RANGE);
              serializer.attribute(null, ATTR_START, String.valueOf(pages[i].getStart()));
              serializer.attribute(null, ATTR_END, String.valueOf(pages[i].getEnd()));
              serializer.endTag(null, TAG_PAGE_RANGE);
            }
          }

          PrintAttributes attributes = printJob.getAttributes();
          if (attributes != null) {
            serializer.startTag(null, TAG_ATTRIBUTES);

            final int colorMode = attributes.getColorMode();
            serializer.attribute(null, ATTR_COLOR_MODE, String.valueOf(colorMode));

            MediaSize mediaSize = attributes.getMediaSize();
            if (mediaSize != null) {
              serializer.startTag(null, TAG_MEDIA_SIZE);
              serializer.attribute(null, ATTR_ID, mediaSize.getId());
              serializer.attribute(null, ATTR_WIDTH_MILS, String.valueOf(mediaSize.getWidthMils()));
              serializer.attribute(
                  null, ATTR_HEIGHT_MILS, String.valueOf(mediaSize.getHeightMils()));
              // We prefer to store only the package name and
              // resource id and fallback to the label.
              if (!TextUtils.isEmpty(mediaSize.mPackageName) && mediaSize.mLabelResId > 0) {
                serializer.attribute(null, ATTR_PACKAGE_NAME, mediaSize.mPackageName);
                serializer.attribute(
                    null, ATTR_LABEL_RES_ID, String.valueOf(mediaSize.mLabelResId));
              } else {
                serializer.attribute(null, ATTR_LABEL, mediaSize.getLabel(getPackageManager()));
              }
              serializer.endTag(null, TAG_MEDIA_SIZE);
            }

            Resolution resolution = attributes.getResolution();
            if (resolution != null) {
              serializer.startTag(null, TAG_RESOLUTION);
              serializer.attribute(null, ATTR_ID, resolution.getId());
              serializer.attribute(
                  null, ATTR_HORIZONTAL_DPI, String.valueOf(resolution.getHorizontalDpi()));
              serializer.attribute(
                  null, ATTR_VERTICAL_DPI, String.valueOf(resolution.getVerticalDpi()));
              serializer.attribute(null, ATTR_LABEL, resolution.getLabel());
              serializer.endTag(null, TAG_RESOLUTION);
            }

            Margins margins = attributes.getMinMargins();
            if (margins != null) {
              serializer.startTag(null, TAG_MARGINS);
              serializer.attribute(null, ATTR_LEFT_MILS, String.valueOf(margins.getLeftMils()));
              serializer.attribute(null, ATTR_TOP_MILS, String.valueOf(margins.getTopMils()));
              serializer.attribute(null, ATTR_RIGHT_MILS, String.valueOf(margins.getRightMils()));
              serializer.attribute(null, ATTR_BOTTOM_MILS, String.valueOf(margins.getBottomMils()));
              serializer.endTag(null, TAG_MARGINS);
            }

            serializer.endTag(null, TAG_ATTRIBUTES);
          }

          PrintDocumentInfo documentInfo = printJob.getDocumentInfo();
          if (documentInfo != null) {
            serializer.startTag(null, TAG_DOCUMENT_INFO);
            serializer.attribute(null, ATTR_NAME, documentInfo.getName());
            serializer.attribute(
                null, ATTR_CONTENT_TYPE, String.valueOf(documentInfo.getContentType()));
            serializer.attribute(
                null, ATTR_PAGE_COUNT, String.valueOf(documentInfo.getPageCount()));
            serializer.attribute(null, ATTR_DATA_SIZE, String.valueOf(documentInfo.getDataSize()));
            serializer.endTag(null, TAG_DOCUMENT_INFO);
          }

          Bundle advancedOptions = printJob.getAdvancedOptions();
          if (advancedOptions != null) {
            serializer.startTag(null, TAG_ADVANCED_OPTIONS);
            for (String key : advancedOptions.keySet()) {
              Object value = advancedOptions.get(key);
              if (value instanceof String) {
                String stringValue = (String) value;
                serializer.startTag(null, TAG_ADVANCED_OPTION);
                serializer.attribute(null, ATTR_KEY, key);
                serializer.attribute(null, ATTR_TYPE, TYPE_STRING);
                serializer.attribute(null, ATTR_VALUE, stringValue);
                serializer.endTag(null, TAG_ADVANCED_OPTION);
              } else if (value instanceof Integer) {
                String intValue = Integer.toString((Integer) value);
                serializer.startTag(null, TAG_ADVANCED_OPTION);
                serializer.attribute(null, ATTR_KEY, key);
                serializer.attribute(null, ATTR_TYPE, TYPE_INT);
                serializer.attribute(null, ATTR_VALUE, intValue);
                serializer.endTag(null, TAG_ADVANCED_OPTION);
              }
            }
            serializer.endTag(null, TAG_ADVANCED_OPTIONS);
          }

          serializer.endTag(null, TAG_JOB);

          if (DEBUG_PERSISTENCE) {
            Log.i(LOG_TAG, "[PERSISTED] " + printJob);
          }
        }

        serializer.endTag(null, TAG_SPOOLER);
        serializer.endDocument();
        mStatePersistFile.finishWrite(out);
        if (DEBUG_PERSISTENCE) {
          Log.i(LOG_TAG, "[PERSIST END]");
        }
      } catch (IOException e) {
        Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e);
        mStatePersistFile.failWrite(out);
      } finally {
        IoUtils.closeQuietly(out);
      }
    }
 /**
  * Puts an advanced (printer specific) option.
  *
  * @param key The option key.
  * @param value The option value.
  */
 public void putAdvancedOption(@NonNull String key, int value) {
   if (mPrototype.mAdvancedOptions == null) {
     mPrototype.mAdvancedOptions = new Bundle();
   }
   mPrototype.mAdvancedOptions.putInt(key, value);
 }
    @Override
    public void onLoadFinished(Loader<List<PrintJobInfo>> loader, List<PrintJobInfo> printJobs) {
      if (printJobs == null || printJobs.isEmpty()) {
        getPreferenceScreen().removePreference(mActivePrintJobsCategory);
      } else {
        if (getPreferenceScreen().findPreference(PRINT_JOBS_CATEGORY) == null) {
          getPreferenceScreen().addPreference(mActivePrintJobsCategory);
        }

        mActivePrintJobsCategory.removeAll();

        final int printJobCount = printJobs.size();
        for (int i = 0; i < printJobCount; i++) {
          PrintJobInfo printJob = printJobs.get(i);

          PreferenceScreen preference =
              getPreferenceManager().createPreferenceScreen(getActivity());

          preference.setPersistent(false);
          preference.setFragment(PrintJobSettingsFragment.class.getName());
          preference.setKey(printJob.getId().flattenToString());

          switch (printJob.getState()) {
            case PrintJobInfo.STATE_QUEUED:
            case PrintJobInfo.STATE_STARTED:
              {
                if (!printJob.isCancelling()) {
                  preference.setTitle(
                      getString(R.string.print_printing_state_title_template, printJob.getLabel()));
                } else {
                  preference.setTitle(
                      getString(
                          R.string.print_cancelling_state_title_template, printJob.getLabel()));
                }
              }
              break;

            case PrintJobInfo.STATE_FAILED:
              {
                preference.setTitle(
                    getString(R.string.print_failed_state_title_template, printJob.getLabel()));
              }
              break;

            case PrintJobInfo.STATE_BLOCKED:
              {
                if (!printJob.isCancelling()) {
                  preference.setTitle(
                      getString(R.string.print_blocked_state_title_template, printJob.getLabel()));
                } else {
                  preference.setTitle(
                      getString(
                          R.string.print_cancelling_state_title_template, printJob.getLabel()));
                }
              }
              break;
          }

          preference.setSummary(
              getString(
                  R.string.print_job_summary,
                  printJob.getPrinterName(),
                  DateUtils.formatSameDayTime(
                      printJob.getCreationTime(),
                      printJob.getCreationTime(),
                      DateFormat.SHORT,
                      DateFormat.SHORT)));

          switch (printJob.getState()) {
            case PrintJobInfo.STATE_QUEUED:
            case PrintJobInfo.STATE_STARTED:
              {
                preference.setIcon(R.drawable.ic_print);
              }
              break;

            case PrintJobInfo.STATE_FAILED:
            case PrintJobInfo.STATE_BLOCKED:
              {
                preference.setIcon(R.drawable.ic_print_error);
              }
              break;
          }

          Bundle extras = preference.getExtras();
          extras.putString(EXTRA_PRINT_JOB_ID, printJob.getId().flattenToString());

          mActivePrintJobsCategory.addPreference(preference);
        }
      }
    }
    private boolean parsePrintJob(XmlPullParser parser) throws IOException, XmlPullParserException {
      skipEmptyTextTags(parser);
      if (!accept(parser, XmlPullParser.START_TAG, TAG_JOB)) {
        return false;
      }

      PrintJobInfo printJob = new PrintJobInfo();

      PrintJobId printJobId =
          PrintJobId.unflattenFromString(parser.getAttributeValue(null, ATTR_ID));
      printJob.setId(printJobId);
      String label = parser.getAttributeValue(null, ATTR_LABEL);
      printJob.setLabel(label);
      final int state = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATE));
      printJob.setState(state);
      final int appId = Integer.parseInt(parser.getAttributeValue(null, ATTR_APP_ID));
      printJob.setAppId(appId);
      String tag = parser.getAttributeValue(null, ATTR_TAG);
      printJob.setTag(tag);
      String creationTime = parser.getAttributeValue(null, ATTR_CREATION_TIME);
      printJob.setCreationTime(Long.parseLong(creationTime));
      String copies = parser.getAttributeValue(null, ATTR_COPIES);
      printJob.setCopies(Integer.parseInt(copies));
      String printerName = parser.getAttributeValue(null, ATTR_PRINTER_NAME);
      printJob.setPrinterName(printerName);
      String stateReason = parser.getAttributeValue(null, ATTR_STATE_REASON);
      printJob.setStateReason(stateReason);
      String cancelling = parser.getAttributeValue(null, ATTR_CANCELLING);
      printJob.setCancelling(
          !TextUtils.isEmpty(cancelling) ? Boolean.parseBoolean(cancelling) : false);

      parser.next();

      skipEmptyTextTags(parser);
      if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) {
        String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
        ComponentName service =
            ComponentName.unflattenFromString(parser.getAttributeValue(null, ATTR_SERVICE_NAME));
        printJob.setPrinterId(new PrinterId(service, localId));
        parser.next();
        skipEmptyTextTags(parser);
        expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
        parser.next();
      }

      skipEmptyTextTags(parser);
      List<PageRange> pageRanges = null;
      while (accept(parser, XmlPullParser.START_TAG, TAG_PAGE_RANGE)) {
        final int start = Integer.parseInt(parser.getAttributeValue(null, ATTR_START));
        final int end = Integer.parseInt(parser.getAttributeValue(null, ATTR_END));
        PageRange pageRange = new PageRange(start, end);
        if (pageRanges == null) {
          pageRanges = new ArrayList<PageRange>();
        }
        pageRanges.add(pageRange);
        parser.next();
        skipEmptyTextTags(parser);
        expect(parser, XmlPullParser.END_TAG, TAG_PAGE_RANGE);
        parser.next();
        skipEmptyTextTags(parser);
      }
      if (pageRanges != null) {
        PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
        pageRanges.toArray(pageRangesArray);
        printJob.setPages(pageRangesArray);
      }

      skipEmptyTextTags(parser);
      if (accept(parser, XmlPullParser.START_TAG, TAG_ATTRIBUTES)) {

        PrintAttributes.Builder builder = new PrintAttributes.Builder();

        String colorMode = parser.getAttributeValue(null, ATTR_COLOR_MODE);
        builder.setColorMode(Integer.parseInt(colorMode));

        parser.next();

        skipEmptyTextTags(parser);
        if (accept(parser, XmlPullParser.START_TAG, TAG_MEDIA_SIZE)) {
          String id = parser.getAttributeValue(null, ATTR_ID);
          label = parser.getAttributeValue(null, ATTR_LABEL);
          final int widthMils = Integer.parseInt(parser.getAttributeValue(null, ATTR_WIDTH_MILS));
          final int heightMils = Integer.parseInt(parser.getAttributeValue(null, ATTR_HEIGHT_MILS));
          String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
          String labelResIdString = parser.getAttributeValue(null, ATTR_LABEL_RES_ID);
          final int labelResId =
              (labelResIdString != null) ? Integer.parseInt(labelResIdString) : 0;
          label = parser.getAttributeValue(null, ATTR_LABEL);
          MediaSize mediaSize =
              new MediaSize(id, label, packageName, widthMils, heightMils, labelResId);
          builder.setMediaSize(mediaSize);
          parser.next();
          skipEmptyTextTags(parser);
          expect(parser, XmlPullParser.END_TAG, TAG_MEDIA_SIZE);
          parser.next();
        }

        skipEmptyTextTags(parser);
        if (accept(parser, XmlPullParser.START_TAG, TAG_RESOLUTION)) {
          String id = parser.getAttributeValue(null, ATTR_ID);
          label = parser.getAttributeValue(null, ATTR_LABEL);
          final int horizontalDpi =
              Integer.parseInt(parser.getAttributeValue(null, ATTR_HORIZONTAL_DPI));
          final int verticalDpi =
              Integer.parseInt(parser.getAttributeValue(null, ATTR_VERTICAL_DPI));
          Resolution resolution = new Resolution(id, label, horizontalDpi, verticalDpi);
          builder.setResolution(resolution);
          parser.next();
          skipEmptyTextTags(parser);
          expect(parser, XmlPullParser.END_TAG, TAG_RESOLUTION);
          parser.next();
        }

        skipEmptyTextTags(parser);
        if (accept(parser, XmlPullParser.START_TAG, TAG_MARGINS)) {
          final int leftMils = Integer.parseInt(parser.getAttributeValue(null, ATTR_LEFT_MILS));
          final int topMils = Integer.parseInt(parser.getAttributeValue(null, ATTR_TOP_MILS));
          final int rightMils = Integer.parseInt(parser.getAttributeValue(null, ATTR_RIGHT_MILS));
          final int bottomMils = Integer.parseInt(parser.getAttributeValue(null, ATTR_BOTTOM_MILS));
          Margins margins = new Margins(leftMils, topMils, rightMils, bottomMils);
          builder.setMinMargins(margins);
          parser.next();
          skipEmptyTextTags(parser);
          expect(parser, XmlPullParser.END_TAG, TAG_MARGINS);
          parser.next();
        }

        printJob.setAttributes(builder.build());

        skipEmptyTextTags(parser);
        expect(parser, XmlPullParser.END_TAG, TAG_ATTRIBUTES);
        parser.next();
      }

      skipEmptyTextTags(parser);
      if (accept(parser, XmlPullParser.START_TAG, TAG_DOCUMENT_INFO)) {
        String name = parser.getAttributeValue(null, ATTR_NAME);
        final int pageCount = Integer.parseInt(parser.getAttributeValue(null, ATTR_PAGE_COUNT));
        final int contentType = Integer.parseInt(parser.getAttributeValue(null, ATTR_CONTENT_TYPE));
        final int dataSize = Integer.parseInt(parser.getAttributeValue(null, ATTR_DATA_SIZE));
        PrintDocumentInfo info =
            new PrintDocumentInfo.Builder(name)
                .setPageCount(pageCount)
                .setContentType(contentType)
                .build();
        printJob.setDocumentInfo(info);
        info.setDataSize(dataSize);
        parser.next();
        skipEmptyTextTags(parser);
        expect(parser, XmlPullParser.END_TAG, TAG_DOCUMENT_INFO);
        parser.next();
      }

      skipEmptyTextTags(parser);
      if (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTIONS)) {
        parser.next();
        skipEmptyTextTags(parser);
        Bundle advancedOptions = new Bundle();
        while (accept(parser, XmlPullParser.START_TAG, TAG_ADVANCED_OPTION)) {
          String key = parser.getAttributeValue(null, ATTR_KEY);
          String value = parser.getAttributeValue(null, ATTR_VALUE);
          String type = parser.getAttributeValue(null, ATTR_TYPE);
          if (TYPE_STRING.equals(type)) {
            advancedOptions.putString(key, value);
          } else if (TYPE_INT.equals(type)) {
            advancedOptions.putInt(key, Integer.valueOf(value));
          }
          parser.next();
          skipEmptyTextTags(parser);
          expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTION);
          parser.next();
          skipEmptyTextTags(parser);
        }
        printJob.setAdvancedOptions(advancedOptions);
        skipEmptyTextTags(parser);
        expect(parser, XmlPullParser.END_TAG, TAG_ADVANCED_OPTIONS);
        parser.next();
      }

      mPrintJobs.add(printJob);

      if (DEBUG_PERSISTENCE) {
        Log.i(LOG_TAG, "[RESTORED] " + printJob);
      }

      skipEmptyTextTags(parser);
      expect(parser, XmlPullParser.END_TAG, TAG_JOB);

      return true;
    }
 /**
  * Sets the number of copies.
  *
  * @param copies The number of copies.
  */
 public void setCopies(@IntRange(from = 1) int copies) {
   mPrototype.mCopies = copies;
 }