// 检查缓存目录中是否已经下载过文件
  private String checkFromCache(DownloadRequest request) {
    if (request != null && !TextUtils.isEmpty(request.mDownloadUrl)) {
      String saveUrl =
          mDownloadFilenameCreateListener != null
              ? mDownloadFilenameCreateListener.onFilenameCreateWithDownloadUrl(
                  request.mDownloadUrl)
              : mDefaultDownloadFilenameCreateListener.onFilenameCreateWithDownloadUrl(
                  request.mDownloadUrl);
      if (TextUtils.isEmpty(DOWNLOADED_FILE_DIR)) {
        return null;
      }
      File dir = new File(DOWNLOADED_FILE_DIR);
      if (!dir.exists() || dir.isFile()) {
        return null;
      }
      String extension =
          TextUtils.isEmpty(request.mFileExtension) ? "" : "." + request.mFileExtension;
      File cachedFile = new File(DOWNLOADED_FILE_DIR + saveUrl + extension);
      if (cachedFile.exists()) {

        if (DEBUG) {
          CommonUtilsConfig.LOGD_WITH_TIME(
              "<<<<< [[find in cache]] >>>>> ::::::::: " + cachedFile.getAbsolutePath());
        }
        return cachedFile.getAbsolutePath();
      }
    }
    if (DEBUG) {
      CommonUtilsConfig.LOGD_WITH_TIME(
          "<<<<< [[can not find in cache]] >>>>> ::::::::: " + request.toString());
    }
    return null;
  }
  /**
   * 将下载好的文件从缓存目录移动到下载完成的目录
   *
   * @param cachedFile
   * @param extension
   * @return
   */
  private String mvFileToDownloadedDir(String cachedFile, String extension) {
    CommonUtilsConfig.LOGD("----- move cached file to + " + DOWNLOADED_FILE_DIR);
    File dir = new File(DOWNLOADED_FILE_DIR);
    if (!dir.exists() || !dir.isDirectory()) {
      dir.delete();
      dir.mkdirs();
    }

    File file = new File(cachedFile);
    String ext = TextUtils.isEmpty(extension) ? "" : "." + extension;
    File newFile = new File(dir.getAbsolutePath() + "/" + file.getName() + ext);
    //		// 重命名成功
    if (CommonUtilsRuntime.isExternalStorageAvailable() && file.renameTo(newFile)) {
      CommonUtilsConfig.LOGD(
          "----- move cached file to + "
              + newFile.getAbsolutePath()
              + " successfully InstallApp=======");
      return newFile.getAbsolutePath();
    }

    // 如果重命名失败,则通过拷贝实现

    InputStream is = null;
    OutputStream os = null;
    try {
      is = new FileInputStream(file);
      os = null;
      if (dir.getAbsolutePath().startsWith("/data/data")) {
        CommonUtilsConfig.LOGD(
            "open world readable file" + " successfully InstallApp=======" + file.getName() + ext);
        os = mContext.openFileOutput(file.getName() + ext, Context.MODE_WORLD_READABLE);
      } else {
        CommonUtilsConfig.LOGD("new FileOutputStream, InstallApp");
        os = new FileOutputStream(newFile);
      }
      CommonUtilsConfig.LOGD(
          "----- move cached file to + "
              + newFile.getAbsolutePath()
              + " successfully InstallApp=======");
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    if (FileUtil.copy(is, os)) {
      file.delete();
      return newFile.getAbsolutePath();
    }

    return null;
  }
  private DownloadRequest findRequestCanOperate(ArrayList<DownloadRequest> requestList) {
    if (DEBUG) {
      CommonUtilsConfig.LOGD_WITH_TIME("<<<<< [[findRequestCanOperate]] >>>>>");
    }

    synchronized (requestList) {
      for (DownloadRequest r : requestList) {
        if (!r.requestIsOperating.get()) {
          r.requestIsOperating.set(true);

          if (DEBUG) {
            CommonUtilsConfig.LOGD_WITH_TIME(
                "<<<<< [[findRequestCanOperate]] end findRequestCanOperate >>>>>");
          }
          return r;
        }
      }

      return null;
    }
  }
  private void waitforUrl() {
    try {
      synchronized (objLock) {
        if (mRequestList.size() == 0 && !bIsWaiting) {
          bIsWaiting = true;

          if (DEBUG) {
            CommonUtilsConfig.LOGD("entry into [[waitforUrl]] for " + DEFAULT_KEEPALIVE + "ms");
          }
          objLock.wait(mKeepAlive);

          if (DEBUG) {
            CommonUtilsConfig.LOGD("leave [[waitforUrl]] for " + DEFAULT_KEEPALIVE + "ms");
          }
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      if (DEBUG) {
        CommonUtilsConfig.LOGD("Excption : ", e);
      }
    }
    bIsWaiting = false;
  }
  @Override
  public void run() {
    while (!bIsStop) {
      waitforUrl();

      if (DEBUG) {
        CommonUtilsConfig.LOGD_WITH_TIME("<<<<< [[run]] >>>>>");
      }
      synchronized (mRequestList) {
        if (mRequestList.size() == 0) {
          // bIsRunning = false;
          bIsStop = true;
          break;
        }
      }

      if (DEBUG) {
        CommonUtilsConfig.LOGD_WITH_TIME("<<<<< [[run]]  end synchronized (mRequestList) >>>>>");
      }

      DownloadRequest request = null;
      try {
        request = findRequestCanOperate(mRequestList);
        if (request == null) {
          bIsStop = true;
        }
        if (request != null && request.mStatus != DownloadRequest.STATUS_CANCEL) {
          if (DEBUG) {
            CommonUtilsConfig.LOGD(
                "================ <<" + Thread.currentThread().getName() + ">> working on : ");
            CommonUtilsConfig.LOGD("begin operate one request : " + request.toString());
            CommonUtilsConfig.LOGD("============================================");
          }

          String cacheFile =
              InternetUtils.requestBigResourceWithCache(
                  mContext, request.mDownloadUrl, request.getHeaders());

          if (DEBUG) {
            CommonUtilsConfig.LOGD("----- after get the cache file : " + cacheFile + " =======");
          }
          if (!TextUtils.isEmpty(cacheFile)) {
            // 将文件移动到下载完成的页面
            String filePath = mvFileToDownloadedDir(cacheFile, request.mFileExtension);
            if (!TextUtils.isEmpty(filePath)) {
              // notify success
              // 将文件移动到下载完成的页面
              DownloadResponse response = tryToHandleDownloadFile(filePath, request);
              if (response != null) {
                mSuccessHandler.notifyAll(-1, -1, response);
                handleResponseByListener(DOWNLOAD_SUCCESS, request.mDownloadUrl, response, false);
                removeRequest(request);
                continue;
              } else {
                handleResponseByListener(DOWNLOAD_FAILED, request.mDownloadUrl, request, false);
                mFailedHandler.notifyAll(-1, -1, request);
                continue;
              }
            } else {
              handleResponseByListener(DOWNLOAD_FAILED, request.mDownloadUrl, request, false);
              mFailedHandler.notifyAll(-1, -1, request);
              continue;
            }
          }

          if (request.getmStatus() != DownloadRequest.STATUS_CANCEL) {
            handleResponseByListener(DOWNLOAD_FAILED, request.mDownloadUrl, request, false);
            mFailedHandler.notifyAll(-1, -1, request);
          } else {
            handleResponseByListener(DOWNLOAD_FAILED, request.mDownloadUrl, request, true);
          }

          if (DEBUG) {
            CommonUtilsConfig.LOGD("success end operate one request : " + request);
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
        if (DEBUG) {
          CommonUtilsConfig.LOGD("Exception : ", e);
          CommonUtilsConfig.LOGD("exception end operate one request : " + request);
          CommonUtilsConfig.LOGD(e.getStackTrace().toString());
        }

        if (request.getmStatus() != DownloadRequest.STATUS_CANCEL) {
          handleResponseByListener(DOWNLOAD_FAILED, request.mDownloadUrl, request, false);
          mFailedHandler.notifyAll(-1, -1, request);
        } else {
          handleResponseByListener(DOWNLOAD_FAILED, request.mDownloadUrl, request, true);
        }
      }

      removeRequest(request);
    }

    System.gc();
  }
  @Override
  public String onInputStreamReturn(String requestUrl, InputStream is) {
    // if (!UtilsRuntime.isSDCardReady()) {
    // UtilsConfig.LOGD("return because unmount the sdcard");
    // return null;
    // }

    if (DEBUG) {
      CommonUtilsConfig.LOGD("");
      CommonUtilsConfig.LOGD("//-------------------------------------------------");
      CommonUtilsConfig.LOGD("||");
      CommonUtilsConfig.LOGD("|| [[FileDownloader::onInputStreamReturn]] : ");
      CommonUtilsConfig.LOGD("||      try to download [[BIG]] file with url : " + requestUrl);
      CommonUtilsConfig.LOGD("||");
      CommonUtilsConfig.LOGD("\\-------------------------------------------------");
      CommonUtilsConfig.LOGD("");
    }

    if (is != null) {
      String saveUrl =
          mDownloadFilenameCreateListener != null
              ? mDownloadFilenameCreateListener.onFilenameCreateWithDownloadUrl(requestUrl)
              : mDefaultDownloadFilenameCreateListener.onFilenameCreateWithDownloadUrl(requestUrl);
      File bigCacheFile = new File(INPUT_STREAM_CACHE_PATH);
      if (!bigCacheFile.exists() || !bigCacheFile.isDirectory()) {
        bigCacheFile.delete();
        bigCacheFile.mkdirs();
      }

      long curTime = 0;
      if (DEBUG) {
        CommonUtilsConfig.LOGD(
            "try to download from inputstream to local path = "
                + INPUT_STREAM_CACHE_PATH
                + saveUrl
                + " for orgin URL : "
                + requestUrl);
        curTime = System.currentTimeMillis();
      }

      // download file
      int totalSize = 0;
      try {
        totalSize = is.available();
      } catch (Exception e) {
        e.printStackTrace();
      }

      long downloadSize = 0;
      String savePath = null;
      String targetPath = INPUT_STREAM_CACHE_PATH + saveUrl;
      byte[] buffer = new byte[4096 * 2];
      File f = new File(targetPath);
      int len;
      OutputStream os = null;
      boolean isClosed = false;
      try {
        if (f.exists()) {
          downloadSize = f.length();
        }

        os = new FileOutputStream(f, true);
        while ((len = is.read(buffer)) != -1) {
          os.write(buffer, 0, len);

          // add listener to Notify UI
          downloadSize += len;
          handleProcess(requestUrl, totalSize, (int) downloadSize);

          if (RUNTIME_CLOSE_SUPPORTED) {
            DownloadRequest r = findCacelRequest(requestUrl);
            if (r != null && r.mStatus == DownloadRequest.STATUS_CANCEL) {
              CommonUtilsConfig.LOGD("try to close is >>>>>>>>>>>>>>>>>>>>");
              is.close();
              isClosed = true;
            }
          }
        }
        savePath = targetPath;
      } catch (Exception ex) {
        ex.printStackTrace();
      } finally {
        if (os != null) {
          try {
            os.close();
          } catch (Exception e) {
            e.printStackTrace();
          }
        }

        buffer = null;
      }
      // end download

      try {
        if (!isClosed) {
          is.close();
        }
      } catch (Exception e) {
        e.printStackTrace();
      }

      if (!isClosed && !TextUtils.isEmpty(savePath) && checkInputStreamDownloadFile(savePath)) {
        if (DEBUG) {
          long successTime = System.currentTimeMillis();
          CommonUtilsConfig.LOGD(
              "[[onInputStreamReturn]] save Request url : "
                  + saveUrl
                  + " success ||||||| and the saved file size : "
                  + FileUtil.convertStorage(new File(savePath).length())
                  + ", save cost time = "
                  + (successTime - curTime)
                  + "ms");
        }

        return savePath;
      } else {
        // 遗留文件,用于下次的断点下载
        if (DEBUG) {
          CommonUtilsConfig.LOGD(
              "===== failed to downlaod requestUrl : "
                  + requestUrl
                  + " beacuse the debug 断点 =====");
        }
        return null;
      }
    } else {
      if (DEBUG) {
        CommonUtilsConfig.LOGD(
            "===== failed to downlaod requestUrl : "
                + requestUrl
                + " beacuse requestUrl is NULL =====");
      }
    }

    return null;
  }
  /**
   * 新提交的request会默认
   *
   * @param request
   * @return
   */
  public boolean postRequest(DownloadRequest request) {
    if (mRequestList == null || request == null || TextUtils.isEmpty(request.mDownloadUrl)) {
      return false;
    }

    if (DEBUG) {
      CommonUtilsConfig.LOGD_WITH_TIME(
          "<<<<< [[postRequest]] >>>>> ::::::::: " + request.toString());
    }

    // 检查是否已经下载过此request对应的文件
    String cachedFile = checkFromCache(request);
    if (!TextUtils.isEmpty(cachedFile)) {
      File file = new File(cachedFile);
      if (file.exists()) {
        DownloadResponse response = tryToHandleDownloadFile(cachedFile, request);
        if (response != null) {
          mSuccessHandler.notifyAll(-1, -1, response);
          handleProcess(request.mDownloadUrl, (int) file.length(), (int) file.length());
        }
        return true;
      }
    }

    synchronized (mRequestList) {
      boolean contain = false;
      for (DownloadRequest r : mRequestList) {
        if (r.mUrlHashCode == request.mUrlHashCode) {
          contain = true;
          break;
        }
      }
      if (!contain) {
        // mRequestList.add(request);
        // 将最新添加的任务放在下载队列的最前面
        if (mLastInFirstDownload) {
          mRequestList.add(0, request);
        } else {
          mRequestList.add(request);
        }

        if (DEBUG) {
          CommonUtilsConfig.LOGD(
              "postRequest, add request : " + request.toString() + " into download list");
        }
      }
      bIsStop = false;

      ThreadPoolSnapShot tss =
          CustomThreadPool.getInstance()
              .getSpecialThreadSnapShot(FileDownloader.class.getSimpleName());
      if (tss == null) {
        return false;
      } else {
        if (tss.taskCount < tss.ALLOWED_MAX_TAKS) {
          if (DEBUG) {
            CommonUtilsConfig.LOGD("entry into [[postRequest]] to start process ");
          }
          processWorks();
        }
      }
    }
    if (DEBUG) {
      CommonUtilsConfig.LOGD_WITH_TIME(
          "<<<<< [[postRequest]]  end synchronized (mRequestList) >>>>>");
    }

    synchronized (objLock) {
      if (bIsWaiting) {
        bIsWaiting = false;

        if (DEBUG) {
          CommonUtilsConfig.LOGD("try to notify download process begin");
        }
        objLock.notify();
      }
    }

    if (DEBUG) {
      CommonUtilsConfig.LOGD_WITH_TIME("<<<<< [[postRequest]]  end synchronized (objLock) >>>>>");
    }

    return true;
  }