public byte getStatus(final int id) {
    final FileDownloadModel model = mHelper.find(id);
    if (model == null) {
      return FileDownloadStatus.INVALID_STATUS;
    }

    return model.getStatus();
  }
  public long getTotal(final int id) {
    final FileDownloadModel model = mHelper.find(id);
    if (model == null) {
      return 0;
    }

    return model.getTotal();
  }
  public boolean clearTaskData(int id) {
    if (id == 0) {
      FileDownloadLog.w(this, "The task[%d] id is invalid, can't clear it.", id);
      return false;
    }

    if (isDownloading(id)) {
      FileDownloadLog.w(this, "The task[%d] is downloading, can't clear it.", id);
      return false;
    }

    mHelper.remove(id);
    return true;
  }
  public boolean pause(final int id) {
    final FileDownloadModel model = mHelper.find(id);
    if (model == null) {
      return false;
    }

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.d(this, "paused %d", id);
    }

    mThreadPool.cancel(id);
    /**
     * 耦合 by {@link FileDownloadRunnable#run()} 中的 {@link
     * com.squareup.okhttp.Request.Builder#tag(Object)} 目前在okHttp里还是每个单独任务
     */
    // 之所以注释掉,不想这里回调error,okHttp中会根据okHttp所在被cancel的情况抛error
    //        client.cancel(id);
    return true;
  }
  // synchronize for safe: check downloading, check resume, update data, execute runnable
  public synchronized void start(
      final String url,
      final String path,
      final boolean pathAsDirectory,
      final int callbackProgressTimes,
      final int callbackProgressMinIntervalMillis,
      final int autoRetryTimes,
      final boolean forceReDownload,
      final FileDownloadHeader header) {
    final int id = FileDownloadUtils.generateId(url, path, pathAsDirectory);
    FileDownloadModel model = mHelper.find(id);

    if (!pathAsDirectory && model == null) {
      // try dir data.
      final int dirCaseId =
          FileDownloadUtils.generateId(url, FileDownloadUtils.getParent(path), true);
      model = mHelper.find(dirCaseId);
      if (model != null && path.equals(model.getTargetFilePath())) {
        if (FileDownloadLog.NEED_LOG) {
          FileDownloadLog.d(this, "task[%d] find model by dirCaseId[%d]", id, dirCaseId);
        }
      }
    }

    if (FileDownloadHelper.inspectAndInflowDownloading(id, model, this)) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(this, "has already started download %d", id);
      }
      return;
    }

    final String targetFilePath =
        model != null
            ? model.getTargetFilePath()
            : FileDownloadUtils.getTargetFilePath(path, pathAsDirectory, null);

    if (FileDownloadHelper.inspectAndInflowDownloaded(id, targetFilePath, forceReDownload)) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(this, "has already completed downloading %d", id);
      }
      return;
    }

    // real start
    // - create model
    boolean needUpdate2DB;
    if (model != null
        && (model.getStatus() == FileDownloadStatus.paused
            || model.getStatus() == FileDownloadStatus.error) // FileDownloadRunnable invoke
    // #isBreakpointAvailable to determine whether it is really invalid.
    ) {
      if (model.getId() != id) {
        // in try dir case.
        mHelper.remove(model.getId());
        model.setId(id);
        model.setPath(path, pathAsDirectory);

        needUpdate2DB = true;
      } else {
        needUpdate2DB = false;
      }
    } else {
      if (model == null) {
        model = new FileDownloadModel();
      }
      model.setUrl(url);
      model.setPath(path, pathAsDirectory);

      model.setId(id);
      model.setSoFar(0);
      model.setTotal(0);
      model.setStatus(FileDownloadStatus.pending);
      needUpdate2DB = true;
    }

    // - update model to db
    if (needUpdate2DB) {
      mHelper.update(model);
    }

    // - execute
    mThreadPool.execute(
        new FileDownloadRunnable(
            client,
            this,
            model,
            mHelper,
            autoRetryTimes,
            header,
            callbackProgressMinIntervalMillis,
            callbackProgressTimes,
            forceReDownload));
  }
 public boolean isDownloading(int id) {
   return isDownloading(mHelper.find(id));
 }