diff options
author | daniel oeh <daniel.oeh@gmail.com> | 2014-11-10 22:00:49 +0100 |
---|---|---|
committer | daniel oeh <daniel.oeh@gmail.com> | 2014-11-10 22:00:49 +0100 |
commit | 99068c82ccf1ac03153e5eb6e79ff2c610caf3cf (patch) | |
tree | c067d370a9b3d11d1b69632c37300bb2a0c3d55a /core/src | |
parent | ad04a80ae7b2091c94b0d007c2a78d97e7af871d (diff) | |
download | AntennaPod-99068c82ccf1ac03153e5eb6e79ff2c610caf3cf.zip |
Updated picasso library
Use RequestHandler instead of Downloader for extracting bitmaps from media files
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java | 241 | ||||
-rw-r--r-- | core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java | 53 |
2 files changed, 174 insertions, 120 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java index 6ace92800..6d9353a93 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java @@ -1,26 +1,26 @@ package de.danoeh.antennapod.core.asynctask; +import android.content.ContentResolver; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.media.MediaMetadataRetriever; import android.net.Uri; import android.util.Log; -import android.webkit.MimeTypeMap; import com.squareup.picasso.Cache; -import com.squareup.picasso.Downloader; import com.squareup.picasso.LruCache; import com.squareup.picasso.OkHttpDownloader; import com.squareup.picasso.Picasso; +import com.squareup.picasso.Request; +import com.squareup.picasso.RequestHandler; -import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; -import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -35,9 +35,6 @@ public class PicassoProvider { private static ExecutorService executorService; private static Cache memoryCache; - private static Picasso defaultPicassoInstance; - private static Picasso mediaMetadataPicassoInstance; - private static synchronized ExecutorService getExecutorService() { if (executorService == null) { executorService = Executors.newFixedThreadPool(3); @@ -52,101 +49,161 @@ public class PicassoProvider { return memoryCache; } - /** - * Returns a Picasso instance that uses an OkHttpDownloader. This instance can only load images - * from image files. - * <p/> - * This instance should be used as long as no images from media files are loaded. - */ - public static synchronized Picasso getDefaultPicassoInstance(Context context) { - Validate.notNull(context); - if (defaultPicassoInstance == null) { - defaultPicassoInstance = new Picasso.Builder(context) - .indicatorsEnabled(DEBUG) - .loggingEnabled(DEBUG) - .downloader(new OkHttpDownloader(context)) - .executor(getExecutorService()) - .memoryCache(getMemoryCache(context)) - .listener(new Picasso.Listener() { - @Override - public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) { - Log.e(TAG, "Failed to load Uri:" + uri.toString()); - e.printStackTrace(); - } - }) - .build(); - } - return defaultPicassoInstance; - } + private static volatile boolean picassoSetup = false; - /** - * Returns a Picasso instance that uses a MediaMetadataRetriever if the given Uri is a media file - * and a default OkHttpDownloader otherwise. - */ - public static synchronized Picasso getMediaMetadataPicassoInstance(Context context) { - Validate.notNull(context); - if (mediaMetadataPicassoInstance == null) { - mediaMetadataPicassoInstance = new Picasso.Builder(context) - .indicatorsEnabled(DEBUG) - .loggingEnabled(DEBUG) - .downloader(new MediaMetadataDownloader(context)) - .executor(getExecutorService()) - .memoryCache(getMemoryCache(context)) - .listener(new Picasso.Listener() { - @Override - public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) { - Log.e(TAG, "Failed to load Uri:" + uri.toString()); - e.printStackTrace(); - } - }) - .build(); + public static synchronized void setupPicassoInstance(Context appContext) { + if (picassoSetup) { + return; } - return mediaMetadataPicassoInstance; + Picasso picasso = new Picasso.Builder(appContext) + .indicatorsEnabled(DEBUG) + .loggingEnabled(DEBUG) + .downloader(new OkHttpDownloader(appContext)) + .addRequestHandler(new MediaRequestHandler(appContext)) + .executor(getExecutorService()) + .memoryCache(getMemoryCache(appContext)) + .listener(new Picasso.Listener() { + @Override + public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) { + Log.e(TAG, "Failed to load Uri:" + uri.toString()); + e.printStackTrace(); + } + }) + .build(); + Picasso.setSingletonInstance(picasso); + picassoSetup = true; } - private static class MediaMetadataDownloader implements Downloader { + private static class MediaRequestHandler extends RequestHandler { + + final MediaMetadataRetriever mmr; + final Context context; - private static final String TAG = "MediaMetadataDownloader"; + public MediaRequestHandler(Context context) { + super(); + this.context = context; + mmr = new MediaMetadataRetriever(); + } - private final OkHttpDownloader okHttpDownloader; + @Override + protected void finalize() throws Throwable { + super.finalize(); + mmr.release(); + } - public MediaMetadataDownloader(Context context) { - Validate.notNull(context); - okHttpDownloader = new OkHttpDownloader(context); + @Override + public boolean canHandleRequest(Request data) { + return StringUtils.equals(data.uri.getScheme(), PicassoImageResource.SCHEME_MEDIA); } @Override - public Response load(Uri uri, boolean b) throws IOException { - if (StringUtils.equals(uri.getScheme(), PicassoImageResource.SCHEME_MEDIA)) { - String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(FilenameUtils.getExtension(uri.getLastPathSegment())); - if (StringUtils.startsWith(type, "image")) { - File imageFile = new File(uri.toString()); - return new Response(new BufferedInputStream(new FileInputStream(imageFile)), true, imageFile.length()); + public Result load(Request data) throws IOException { + Bitmap bitmap = null; + mmr.setDataSource(data.uri.getPath()); + byte[] image = mmr.getEmbeddedPicture(); + if (image != null) { + bitmap = decodeStreamFromByteArray(data, image); + } + if (bitmap == null) { + // check for fallback Uri + String fallbackParam = data.uri.getQueryParameter(PicassoImageResource.PARAM_FALLBACK); + + if (fallbackParam != null) { + Uri fallback = Uri.parse(fallbackParam); + bitmap = decodeStreamFromFile(data, fallback); + } + } + return new Result(bitmap, Picasso.LoadedFrom.DISK); + + } + + /* Copied/Adapted from Picasso RequestHandler classes */ + + private Bitmap decodeStreamFromByteArray(Request data, byte[] bytes) throws IOException { + + final BitmapFactory.Options options = createBitmapOptions(data); + final ByteArrayInputStream in = new ByteArrayInputStream(bytes); + in.mark(0); + if (requiresInSampleSize(options)) { + try { + BitmapFactory.decodeStream(in, null, options); + } finally { + in.reset(); + } + calculateInSampleSize(data.targetWidth, data.targetHeight, options, data); + } + try { + return BitmapFactory.decodeStream(in, null, options); + } finally { + IOUtils.closeQuietly(in); + } + } + + private Bitmap decodeStreamFromFile(Request data, Uri uri) throws IOException { + ContentResolver contentResolver = context.getContentResolver(); + final BitmapFactory.Options options = createBitmapOptions(data); + if (requiresInSampleSize(options)) { + InputStream is = null; + try { + is = contentResolver.openInputStream(uri); + BitmapFactory.decodeStream(is, null, options); + } finally { + IOUtils.closeQuietly(is); + } + calculateInSampleSize(data.targetWidth, data.targetHeight, options, data); + } + InputStream is = contentResolver.openInputStream(uri); + try { + return BitmapFactory.decodeStream(is, null, options); + } finally { + IOUtils.closeQuietly(is); + } + } + + private BitmapFactory.Options createBitmapOptions(Request data) { + final boolean justBounds = data.hasSize(); + final boolean hasConfig = data.config != null; + BitmapFactory.Options options = null; + if (justBounds || hasConfig) { + options = new BitmapFactory.Options(); + options.inJustDecodeBounds = justBounds; + if (hasConfig) { + options.inPreferredConfig = data.config; + } + } + return options; + } + + private static boolean requiresInSampleSize(BitmapFactory.Options options) { + return options != null && options.inJustDecodeBounds; + } + + private static void calculateInSampleSize(int reqWidth, int reqHeight, BitmapFactory.Options options, + Request request) { + calculateInSampleSize(reqWidth, reqHeight, options.outWidth, options.outHeight, options, + request); + } + + private static void calculateInSampleSize(int reqWidth, int reqHeight, int width, int height, + BitmapFactory.Options options, Request request) { + int sampleSize = 1; + if (height > reqHeight || width > reqWidth) { + final int heightRatio; + final int widthRatio; + if (reqHeight == 0) { + sampleSize = (int) Math.floor((float) width / (float) reqWidth); + } else if (reqWidth == 0) { + sampleSize = (int) Math.floor((float) height / (float) reqHeight); } else { - MediaMetadataRetriever mmr = new MediaMetadataRetriever(); - mmr.setDataSource(uri.getPath()); - byte[] data = mmr.getEmbeddedPicture(); - mmr.release(); - - if (data != null) { - return new Response(new ByteArrayInputStream(data), true, data.length); - } else { - - // check for fallback Uri - String fallbackParam = uri.getQueryParameter(PicassoImageResource.PARAM_FALLBACK); - - if (fallbackParam != null) { - String fallback = Uri.decode(Uri.parse(fallbackParam).getPath()); - if (fallback != null) { - File imageFile = new File(fallback); - return new Response(new BufferedInputStream(new FileInputStream(imageFile)), true, imageFile.length()); - } - } - return null; - } + heightRatio = (int) Math.floor((float) height / (float) reqHeight); + widthRatio = (int) Math.floor((float) width / (float) reqWidth); + sampleSize = request.centerInside + ? Math.max(heightRatio, widthRatio) + : Math.min(heightRatio, widthRatio); } } - return okHttpDownloader.load(uri, b); + options.inSampleSize = sampleSize; + options.inJustDecodeBounds = false; } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index 1261c21fe..a5560e3fb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -29,6 +29,8 @@ import android.view.KeyEvent; import android.view.SurfaceHolder; import android.widget.Toast; +import com.squareup.picasso.Picasso; + import org.apache.commons.lang3.StringUtils; import java.io.IOException; @@ -37,7 +39,6 @@ import java.util.List; import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.asynctask.PicassoProvider; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; @@ -291,10 +292,9 @@ public class PlaybackService extends Service { case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: if (status == PlayerStatus.PLAYING) { if (UserPreferences.isPersistNotify()) { - mediaPlayer.pause(false, true); - } - else { - mediaPlayer.pause(true, true); + mediaPlayer.pause(false, true); + } else { + mediaPlayer.pause(true, true); } } else if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) { mediaPlayer.resume(); @@ -315,12 +315,11 @@ public class PlaybackService extends Service { break; case KeyEvent.KEYCODE_MEDIA_PAUSE: if (status == PlayerStatus.PLAYING) { - if (UserPreferences.isPersistNotify()) { - mediaPlayer.pause(false, true); - } - else { - mediaPlayer.pause(true, true); - } + if (UserPreferences.isPersistNotify()) { + mediaPlayer.pause(false, true); + } else { + mediaPlayer.pause(true, true); + } } break; case KeyEvent.KEYCODE_MEDIA_NEXT: @@ -332,11 +331,11 @@ public class PlaybackService extends Service { mediaPlayer.seekDelta(-UserPreferences.getSeekDeltaMs()); break; case KeyEvent.KEYCODE_MEDIA_STOP: - if (status == PlayerStatus.PLAYING) { - mediaPlayer.pause(true, true); - } - stopForeground(true); // gets rid of persistent notification - break; + if (status == PlayerStatus.PLAYING) { + mediaPlayer.pause(true, true); + } + stopForeground(true); // gets rid of persistent notification + break; default: if (info.playable != null && info.playerStatus == PlayerStatus.PLAYING) { // only notify the user about an unknown key event if it is actually doing something String message = String.format(getResources().getString(R.string.unknown_media_key), keycode); @@ -411,11 +410,10 @@ public class PlaybackService extends Service { saveCurrentPosition(false, 0); taskManager.cancelWidgetUpdater(); if (UserPreferences.isPersistNotify() && android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - // do not remove notification on pause based on user pref and whether android version supports expanded notifications - } - else { - // remove notifcation on pause - stopForeground(true); + // do not remove notification on pause based on user pref and whether android version supports expanded notifications + } else { + // remove notifcation on pause + stopForeground(true); } break; @@ -709,7 +707,7 @@ public class PlaybackService extends Service { try { int iconSize = getResources().getDimensionPixelSize( android.R.dimen.notification_large_icon_width); - icon = PicassoProvider.getMediaMetadataPicassoInstance(PlaybackService.this) + icon = Picasso.with(PlaybackService.this) .load(info.playable.getImageUri()) .resize(iconSize, iconSize) .get(); @@ -1005,12 +1003,11 @@ public class PlaybackService extends Service { */ private void pauseIfPauseOnDisconnect() { if (UserPreferences.isPauseOnHeadsetDisconnect()) { - if (UserPreferences.isPersistNotify()) { - mediaPlayer.pause(false, true); - } - else { - mediaPlayer.pause(true, true); - } + if (UserPreferences.isPersistNotify()) { + mediaPlayer.pause(false, true); + } else { + mediaPlayer.pause(true, true); + } } } |