boolean updateKeepAhead(final MessageSnapshot snapshot) {
    if (!FileDownloadStatus.isKeepAhead(getStatus(), snapshot.getStatus())) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(
            this,
            "can't update status change by keep ahead, %d, but the" + " current status is %d, %d",
            status,
            getStatus(),
            getId());
      }
      return false;
    }

    update(snapshot);
    return true;
  }
  boolean updateKeepFlow(final MessageSnapshot snapshot) {
    final int currentStatus = getStatus();
    final int nextStatus = snapshot.getStatus();

    if (FileDownloadStatus.paused == currentStatus && FileDownloadStatus.isIng(nextStatus)) {
      if (FileDownloadLog.NEED_LOG) {
        /**
         * Occur such situation, must be the running-status waiting for turning up in flow thread
         * pool(or binder thread) when there is someone invoked the {@link #pause()} .
         *
         * <p>High concurrent cause.
         */
        FileDownloadLog.d(
            this,
            "High concurrent cause, callback pending, but has already" + " be paused %d",
            getId());
      }
      return true;
    }

    if (!FileDownloadStatus.isKeepFlow(currentStatus, nextStatus)) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(
            this,
            "can't update status change by keep flow, %d, but the" + " current status is %d, %d",
            status,
            getStatus(),
            getId());
      }

      return false;
    }

    update(snapshot);
    return true;
  }
  private void update(final MessageSnapshot snapshot) {
    setStatus(snapshot.getStatus());
    this.isLargeFile = snapshot.isLargeFile();

    switch (snapshot.getStatus()) {
      case FileDownloadStatus.pending:
        this.soFarBytes = snapshot.getLargeSofarBytes();
        this.totalBytes = snapshot.getLargeTotalBytes();

        // notify
        getMessenger().notifyPending(snapshot);
        break;
      case FileDownloadStatus.started:
        // notify
        getMessenger().notifyStarted(snapshot);
        break;
      case FileDownloadStatus.connected:
        this.totalBytes = snapshot.getLargeTotalBytes();
        this.resuming = snapshot.isResuming();
        this.etag = snapshot.getEtag();

        markStartDownload();

        // notify
        getMessenger().notifyConnected(snapshot);
        break;
      case FileDownloadStatus.progress:
        this.soFarBytes = snapshot.getLargeSofarBytes();
        calcSpeed(snapshot.getLargeSofarBytes());

        // notify
        getMessenger().notifyProgress(snapshot);
        break;
        //            case FileDownloadStatus.blockComplete:
        /** Handled by {@link FileDownloadList#removeByCompleted(BaseDownloadTask)} */
        //                break;
      case FileDownloadStatus.retry:
        this.soFarBytes = snapshot.getLargeSofarBytes();
        this.ex = snapshot.getThrowable();
        _setRetryingTimes(snapshot.getRetryingTimes());

        resetSpeed();
        // notify
        getMessenger().notifyRetry(snapshot);
        break;
      case FileDownloadStatus.error:
        this.ex = snapshot.getThrowable();
        this.soFarBytes = snapshot.getLargeSofarBytes();

        calcAverageSpeed(this.soFarBytes);
        // to FileDownloadList
        FileDownloadList.getImpl().remove(this, snapshot);

        break;
      case FileDownloadStatus.paused:
        /** Handled by {@link #pause()} */
        break;
      case FileDownloadStatus.completed:
        this.isReusedOldFile = snapshot.isReusedDownloadedFile();
        if (snapshot.isReusedDownloadedFile()) {
          this.etag = snapshot.getEtag();
        }
        // only carry total data back
        this.soFarBytes = snapshot.getLargeTotalBytes();
        this.totalBytes = snapshot.getLargeTotalBytes();

        calcAverageSpeed(this.soFarBytes);
        // to FileDownloadList
        FileDownloadList.getImpl().remove(this, snapshot);

        break;
      case FileDownloadStatus.warn:
        resetSpeed();
        final int count = FileDownloadList.getImpl().count(getId());
        if (count <= 1) {
          // 1. this progress kill by sys and relive,
          // for add at least one listener
          // or 2. pre downloading task has already completed/error/paused
          // request status
          final int currentStatus = _getStatusFromServer(downloadId);
          FileDownloadLog.w(
              this,
              "warn, but no listener to receive progress, " + "switch to pending %d %d",
              getId(),
              currentStatus);

          //noinspection StatementWithEmptyBody
          if (FileDownloadStatus.isIng(currentStatus)) {
            // ing, has callbacks
            // keep and wait callback

            setStatus(FileDownloadStatus.pending);
            this.totalBytes = snapshot.getLargeTotalBytes();
            this.soFarBytes = snapshot.getLargeSofarBytes();

            markStartDownload();

            ((MessageSnapshot.IWarnMessageSnapshot) snapshot).turnToPending();
            getMessenger().notifyPending(snapshot);
            break;
          } else {
            // already over and no callback
          }
        }

        // to FileDownloadList
        FileDownloadList.getImpl().remove(this, snapshot);
        break;
    }
  }