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