@Override
  @NonNull
  public CacheDownloadLoader.Result loadInBackground() {
    if (mUri == null) {
      return Result.nullInstance();
    }
    final String scheme = mUri.getScheme();
    File cacheFile = null;
    if ("http".equals(scheme) || "https".equals(scheme)) {
      final String uriString = mUri.toString();
      if (uriString == null) return Result.nullInstance();
      cacheFile = mDiskCache.get(uriString);
      if (isValid(cacheFile)) {
        return Result.getInstance(CacheProvider.getCacheUri(uriString));
      }
      try {
        // from SD cache
        ContentLengthInputStream cis;
        final InputStream is = mDownloader.get(uriString);
        if (is == null) return Result.nullInstance();
        try {
          final long length = is.available();
          mHandler.post(new DownloadStartRunnable(this, mListener, length));

          cis = new ContentLengthInputStream(is, length);
          mDiskCache.save(
              uriString,
              cis,
              new IoUtils.CopyListener() {
                @Override
                public boolean onBytesCopied(int current, int total) {
                  mHandler.post(new ProgressUpdateRunnable(mListener, current, total));
                  return !isAbandoned();
                }
              });
          mHandler.post(new DownloadFinishRunnable(this, mListener));
        } finally {
          Utils.closeSilently(is);
        }
        cacheFile = mDiskCache.get(uriString);
        if (isValid(cacheFile)) {
          return Result.getInstance(CacheProvider.getCacheUri(uriString));
        } else {
          mDiskCache.remove(uriString);
          throw new IOException();
        }
      } catch (final Exception e) {
        mHandler.post(new DownloadErrorRunnable(this, mListener, e));
        return Result.getInstance(e);
      }
    }
    return Result.getInstance(mUri);
  }
 protected Result decodeBitmapOnly(final File file, boolean useDecoder) {
   final String path = file.getAbsolutePath();
   final BitmapFactory.Options o = new BitmapFactory.Options();
   o.inJustDecodeBounds = true;
   BitmapFactory.decodeFile(path, o);
   final int width = o.outWidth, height = o.outHeight;
   if (width <= 0 || height <= 0) return Result.getInstance(file, null);
   o.inJustDecodeBounds = false;
   o.inSampleSize = BitmapUtils.computeSampleSize(mFallbackSize / Math.max(width, height));
   final Bitmap bitmap = BitmapFactory.decodeFile(path, o);
   return Result.getInstance(useDecoder, bitmap, o, Exif.getOrientation(file), file);
 }
 @Override
 public TileImageLoader.Result loadInBackground() {
   if (mUri == null) {
     return Result.nullInstance();
   }
   final String scheme = mUri.getScheme();
   if ("http".equals(scheme) || "https".equals(scheme)) {
     final String url = mUri.toString();
     if (url == null) return Result.nullInstance();
     File cacheFile = mDiskCache.get(url);
     if (cacheFile != null) {
       final int cachedValidity = ImageValidator.checkImageValidity(cacheFile);
       if (ImageValidator.isValid(cachedValidity)) {
         // The file is corrupted, so we remove it from
         // cache.
         return decodeBitmapOnly(
             cacheFile, ImageValidator.isValidForRegionDecoder(cachedValidity));
       }
     }
     try {
       // from SD cache
       final InputStream is = mDownloader.getStream(url, new AccountExtra(mAccountId));
       if (is == null) return Result.nullInstance();
       try {
         final long length = is.available();
         mHandler.post(new DownloadStartRunnable(this, mListener, length));
         mDiskCache.save(
             url,
             is,
             new IoUtils.CopyListener() {
               @Override
               public boolean onBytesCopied(int current, int total) {
                 mHandler.post(new ProgressUpdateRunnable(mListener, current));
                 return !isAbandoned();
               }
             });
         mHandler.post(new DownloadFinishRunnable(this, mListener));
       } finally {
         IoUtils.closeSilently(is);
       }
       cacheFile = mDiskCache.get(url);
       final int downloadedValidity = ImageValidator.checkImageValidity(cacheFile);
       if (ImageValidator.isValid(downloadedValidity)) {
         // The file is corrupted, so we remove it from
         // cache.
         return decodeBitmapOnly(
             cacheFile, ImageValidator.isValidForRegionDecoder(downloadedValidity));
       } else {
         mDiskCache.remove(url);
         throw new IOException();
       }
     } catch (final Exception e) {
       mHandler.post(new DownloadErrorRunnable(this, mListener, e));
       return Result.getInstance(cacheFile, e);
     }
   } else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
     final File file = new File(mUri.getPath());
     try {
       return decodeBitmapOnly(
           file, ImageValidator.isValidForRegionDecoder(ImageValidator.checkImageValidity(file)));
     } catch (final Exception e) {
       return Result.getInstance(file, e);
     }
   }
   return Result.nullInstance();
 }