private void runPendingCommand() {
    if (mCurrentCommand != null
        && (mCurrentCommand.isCompleted() || mCurrentCommand.isCanceled())) {
      mCurrentCommand = mNextCommand;
      mNextCommand = null;
    }

    if (mCurrentCommand != null) {
      if (mCurrentCommand.isPending()) {
        mCurrentCommand.run();

        mState = STATE_UPDATING;
      }
    } else {
      mState = STATE_UPDATED;
    }
  }
  public void cancel(boolean force) {
    if (DEBUG) {
      Log.i(LOG_TAG, "[CALLED] cancel(" + force + ")");
    }

    mNextCommand = null;

    if (mState != STATE_UPDATING) {
      return;
    }

    mState = STATE_CANCELING;

    mCurrentCommand.cancel(force);
  }
  public boolean update(PrintAttributes attributes, PageRange[] pages, boolean preview) {
    boolean willUpdate;

    if (DEBUG) {
      Log.i(LOG_TAG, "[CALLED] update()");
    }

    if (hasUpdateError()) {
      throw new IllegalStateException("Cannot update without a clearing the failure");
    }

    if (mState == STATE_INITIAL || mState == STATE_FINISHED || mState == STATE_DESTROYED) {
      throw new IllegalStateException("Cannot update in state:" + stateToString(mState));
    }

    // We schedule a layout if the constraints changed.
    if (!mUpdateSpec.hasSameConstraints(attributes, preview)) {
      willUpdate = true;

      // If there is a current command that is running we ask for a
      // cancellation and start over.
      if (mCurrentCommand != null && (mCurrentCommand.isRunning() || mCurrentCommand.isPending())) {
        mCurrentCommand.cancel(false);
      }

      // Schedule a layout command.
      PrintAttributes oldAttributes =
          mDocumentInfo.attributes != null
              ? mDocumentInfo.attributes
              : new PrintAttributes.Builder().build();
      AsyncCommand command =
          new LayoutCommand(
              mLooper,
              mPrintDocumentAdapter,
              mDocumentInfo,
              oldAttributes,
              attributes,
              preview,
              mCommandResultCallback);
      scheduleCommand(command);

      mState = STATE_UPDATING;
      // If no layout in progress and we don't have all pages - schedule a write.
    } else if ((!(mCurrentCommand instanceof LayoutCommand)
            || (!mCurrentCommand.isPending() && !mCurrentCommand.isRunning()))
        && pages != null
        && !PageRangeUtils.contains(mUpdateSpec.pages, pages, mDocumentInfo.info.getPageCount())) {
      willUpdate = true;

      // Cancel the current write as a new one is to be scheduled.
      if (mCurrentCommand instanceof WriteCommand
          && (mCurrentCommand.isPending() || mCurrentCommand.isRunning())) {
        mCurrentCommand.cancel(false);
      }

      // Schedule a write command.
      AsyncCommand command =
          new WriteCommand(
              mContext,
              mLooper,
              mPrintDocumentAdapter,
              mDocumentInfo,
              mDocumentInfo.info.getPageCount(),
              pages,
              mDocumentInfo.fileProvider,
              mCommandResultCallback);
      scheduleCommand(command);

      mState = STATE_UPDATING;
    } else {
      willUpdate = false;
      if (DEBUG) {
        Log.i(LOG_TAG, "[SKIPPING] No update needed");
      }
    }

    // Keep track of what is requested.
    mUpdateSpec.update(attributes, preview, pages);

    runPendingCommand();

    return willUpdate;
  }