private void handleOnWriteFinished(PageRange[] pages, int sequence) {
      if (sequence != mSequence) {
        return;
      }

      if (DEBUG) {
        Log.i(LOG_TAG, "[CALLBACK] onWriteFinished");
      }

      PageRange[] writtenPages = PageRangeUtils.normalize(pages);
      PageRange[] printedPages =
          PageRangeUtils.computePrintedPages(mPages, writtenPages, mPageCount);

      // Handle if we got invalid pages
      if (printedPages != null) {
        mDocument.writtenPages = writtenPages;
        mDocument.printedPages = printedPages;
        completed();
      } else {
        mDocument.writtenPages = null;
        mDocument.printedPages = null;
        failed(mContext.getString(R.string.print_error_default_message));
      }

      // Release the remote cancellation interface.
      mCancellation = null;

      // Done.
      mWriteDoneCallback.onDone();
    }
 @Override
 public void onDone() {
   if (mCurrentCommand.isCompleted()) {
     if (mCurrentCommand instanceof LayoutCommand) {
       // If there is a next command after a layout is done, then another
       // update was issued and the next command is another layout, so we
       // do nothing. However, if there is no next command we may need to
       // ask for some pages given we do not already have them or we do
       // but the content has changed.
       if (mNextCommand == null) {
         if (mUpdateSpec.pages != null
             && (mDocumentInfo.changed
                 || (mDocumentInfo.info.getPageCount()
                         != PrintDocumentInfo.PAGE_COUNT_UNKNOWN
                     && !PageRangeUtils.contains(
                         mDocumentInfo.writtenPages,
                         mUpdateSpec.pages,
                         mDocumentInfo.info.getPageCount())))) {
           mNextCommand =
               new WriteCommand(
                   mContext,
                   mLooper,
                   mPrintDocumentAdapter,
                   mDocumentInfo,
                   mDocumentInfo.info.getPageCount(),
                   mUpdateSpec.pages,
                   mDocumentInfo.fileProvider,
                   mCommandResultCallback);
         } else {
           if (mUpdateSpec.pages != null) {
             // If we have the requested pages, update which ones to be printed.
             mDocumentInfo.printedPages =
                 PageRangeUtils.computePrintedPages(
                     mUpdateSpec.pages,
                     mDocumentInfo.writtenPages,
                     mDocumentInfo.info.getPageCount());
           }
           // Notify we are done.
           mState = STATE_UPDATED;
           notifyUpdateCompleted();
         }
       }
     } else {
       // We always notify after a write.
       mState = STATE_UPDATED;
       notifyUpdateCompleted();
     }
     runPendingCommand();
   } else if (mCurrentCommand.isFailed()) {
     mState = STATE_FAILED;
     CharSequence error = mCurrentCommand.getError();
     mCurrentCommand = null;
     mNextCommand = null;
     mUpdateSpec.reset();
     notifyUpdateFailed(error);
   } else if (mCurrentCommand.isCanceled()) {
     if (mState == STATE_CANCELING) {
       mState = STATE_CANCELED;
       notifyUpdateCanceled();
     }
     runPendingCommand();
   }
 }
  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;
  }