OSDN Git Service

Eleven: Fix a slight regression with the blur image loading too often
[android-x86/packages-apps-Eleven.git] / src / com / cyngn / eleven / cache / ImageFetcher.java
index 3832c6e..e918d7b 100644 (file)
 
 package com.cyngn.eleven.cache;
 
+import android.content.ContentResolver;
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
 import android.widget.ImageView;
-
 import com.cyngn.eleven.Config;
 import com.cyngn.eleven.MusicPlaybackService;
 import com.cyngn.eleven.cache.PlaylistWorkerTask.PlaylistWorkerType;
 import com.cyngn.eleven.utils.MusicUtils;
 import com.cyngn.eleven.widgets.BlurScrimImage;
 
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
 /**
  * A subclass of {@link ImageWorker} that fetches images from a URL.
  */
 public class ImageFetcher extends ImageWorker {
 
+    private static final int DEFAULT_MAX_IMAGE_HEIGHT = 1024;
+
+    private static final int DEFAULT_MAX_IMAGE_WIDTH = 1024;
+
     private static ImageFetcher sInstance = null;
 
     /**
@@ -81,7 +91,7 @@ public class ImageFetcher extends ImageWorker {
      * Used to fetch the current artwork.
      */
     public void loadCurrentArtwork(final ImageView imageView) {
-        loadImage(generateAlbumCacheKey(MusicUtils.getAlbumName(), MusicUtils.getArtistName()),
+        loadImage(getCurrentCacheKey(),
                 MusicUtils.getArtistName(), MusicUtils.getAlbumName(), MusicUtils.getCurrentAlbumId(),
                 imageView, ImageType.ALBUM);
     }
@@ -90,11 +100,15 @@ public class ImageFetcher extends ImageWorker {
      * Used to fetch the current artwork blurred.
      */
     public void loadCurrentBlurredArtwork(final BlurScrimImage image) {
-        loadBlurImage(generateAlbumCacheKey(MusicUtils.getAlbumName(), MusicUtils.getArtistName()),
+        loadBlurImage(getCurrentCacheKey(),
                 MusicUtils.getArtistName(), MusicUtils.getAlbumName(), MusicUtils.getCurrentAlbumId(),
                 image, ImageType.ALBUM);
     }
 
+    public static String getCurrentCacheKey() {
+        return generateAlbumCacheKey(MusicUtils.getAlbumName(), MusicUtils.getArtistName());
+    }
+
     /**
      * Used to fetch artist images.
      */
@@ -103,6 +117,13 @@ public class ImageFetcher extends ImageWorker {
     }
 
     /**
+     * Used to fetch artist images. It also scales the image to fit the image view, if necessary.
+     */
+    public void loadArtistImage(final String key, final ImageView imageView, boolean scaleImgToView) {
+        loadImage(key, key, null, -1, imageView, ImageType.ARTIST, scaleImgToView);
+    }
+
+    /**
      * Used to fetch the current artist image.
      */
     public void loadCurrentArtistImage(final ImageView imageView) {
@@ -126,6 +147,21 @@ public class ImageFetcher extends ImageWorker {
         if (mImageCache != null) {
             mImageCache.clearCaches();
         }
+
+        // clear the keys of images we've already downloaded
+        sKeys.clear();
+    }
+
+    public void addCacheListener(ICacheListener listener) {
+        if (mImageCache != null) {
+            mImageCache.addCacheListener(listener);
+        }
+    }
+
+    public void removeCacheListener(ICacheListener listener) {
+        if (mImageCache != null) {
+            mImageCache.removeCacheListener(listener);
+        }
     }
 
     /**
@@ -179,9 +215,11 @@ public class ImageFetcher extends ImageWorker {
      * @param albumId    The ID of the current album
      * @param artistName The album artist in case we should have to download
      *                   missing artwork
+     * @param smallArtwork Get the small version of the default artwork if no artwork exists
      * @return The album art as an {@link Bitmap}
      */
-    public Bitmap getArtwork(final String albumName, final long albumId, final String artistName) {
+    public Bitmap getArtwork(final String albumName, final long albumId, final String artistName,
+                             boolean smallArtwork) {
         // Check the disk cache
         Bitmap artwork = null;
 
@@ -196,7 +234,7 @@ public class ImageFetcher extends ImageWorker {
         if (artwork != null) {
             return artwork;
         }
-        return getDefaultArtwork();
+        return getDefaultArtwork(smallArtwork);
     }
 
     /**
@@ -219,4 +257,94 @@ public class ImageFetcher extends ImageWorker {
                 .append(Config.ALBUM_ART_SUFFIX)
                 .toString();
     }
+
+    /**
+     * Decode and sample down a {@link Bitmap} from a Uri.
+     *
+     * @param selectedImage Uri of the Image to decode
+     * @return A {@link Bitmap} sampled down from the original with the same
+     *         aspect ratio and dimensions that are equal to or greater than the
+     *         requested width and height
+     */
+    public static Bitmap decodeSampledBitmapFromUri(ContentResolver cr, final Uri selectedImage) {
+        // First decode with inJustDecodeBounds=true to check dimensions
+        final BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+
+        try {
+            InputStream input = cr.openInputStream(selectedImage);
+            BitmapFactory.decodeStream(input, null, options);
+            input.close();
+
+            if (options.outHeight == -1 || options.outWidth == -1) {
+                return null;
+            }
+
+            // Calculate inSampleSize
+            options.inSampleSize = calculateInSampleSize(options, DEFAULT_MAX_IMAGE_WIDTH,
+                    DEFAULT_MAX_IMAGE_HEIGHT);
+
+            // Decode bitmap with inSampleSize set
+            options.inJustDecodeBounds = false;
+            input = cr.openInputStream(selectedImage);
+            return BitmapFactory.decodeStream(input, null, options);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+            return null;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    /**
+     * Calculate an inSampleSize for use in a
+     * {@link android.graphics.BitmapFactory.Options} object when decoding
+     * bitmaps using the decode* methods from {@link BitmapFactory}. This
+     * implementation calculates the closest inSampleSize that will result in
+     * the final decoded bitmap having a width and height equal to or larger
+     * than the requested width and height. This implementation does not ensure
+     * a power of 2 is returned for inSampleSize which can be faster when
+     * decoding but results in a larger bitmap which isn't as useful for caching
+     * purposes.
+     *
+     * @param options An options object with out* params already populated (run
+     *            through a decode* method with inJustDecodeBounds==true
+     * @param reqWidth The requested width of the resulting bitmap
+     * @param reqHeight The requested height of the resulting bitmap
+     * @return The value to be used for inSampleSize
+     */
+    public static final int calculateInSampleSize(final BitmapFactory.Options options,
+                                                  final int reqWidth, final int reqHeight) {
+        /* Raw height and width of image */
+        final int height = options.outHeight;
+        final int width = options.outWidth;
+        int inSampleSize = 1;
+
+        if (height > reqHeight || width > reqWidth) {
+            if (width > height) {
+                inSampleSize = Math.round((float)height / (float)reqHeight);
+            } else {
+                inSampleSize = Math.round((float)width / (float)reqWidth);
+            }
+
+            // This offers some additional logic in case the image has a strange
+            // aspect ratio. For example, a panorama may have a much larger
+            // width than height. In these cases the total pixels might still
+            // end up being too large to fit comfortably in memory, so we should
+            // be more aggressive with sample down the image (=larger
+            // inSampleSize).
+
+            final float totalPixels = width * height;
+
+            /* More than 2x the requested pixels we'll sample down further */
+            final float totalReqPixelsCap = reqWidth * reqHeight * 2;
+
+            while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
+                inSampleSize++;
+            }
+        }
+        return inSampleSize;
+    }
 }