diff options
author | daniel oeh <daniel.oeh@gmail.com> | 2014-07-27 23:29:47 +0200 |
---|---|---|
committer | daniel oeh <daniel.oeh@gmail.com> | 2014-07-30 12:42:01 +0200 |
commit | 09c4736867acafee9c008caa8ab78f7b3c4cef68 (patch) | |
tree | 04b5ca6258c3449a9ee89fc832edc44c652fe0de /src | |
parent | 460e061d35e45268d3dcfebeba00e7231ce8cfd0 (diff) | |
download | AntennaPod-09c4736867acafee9c008caa8ab78f7b3c4cef68.zip |
Replaced ImageLoader and DiskCache with Picasso
Implemented Picasso Downloaders
Replaced ImageLoader and DiskCache with Picasso
Removed ImageLoader, DiskCache code
Diffstat (limited to 'src')
28 files changed, 968 insertions, 1714 deletions
diff --git a/src/de/danoeh/antennapod/PodcastApp.java b/src/de/danoeh/antennapod/PodcastApp.java index 4c4766327..74628f3d6 100644 --- a/src/de/danoeh/antennapod/PodcastApp.java +++ b/src/de/danoeh/antennapod/PodcastApp.java @@ -3,7 +3,6 @@ package de.danoeh.antennapod; import android.app.Application; import android.content.res.Configuration; import android.util.Log; -import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.preferences.PlaybackPreferences; import de.danoeh.antennapod.preferences.UserPreferences; @@ -36,13 +35,6 @@ public class PodcastApp extends Application { SPAUtil.sendSPAppsQueryFeedsIntent(this); } - @Override - public void onLowMemory() { - super.onLowMemory(); - Log.w(TAG, "Received onLowOnMemory warning. Cleaning image cache..."); - ImageLoader.getInstance().wipeImageCache(); - } - public static float getLogicalDensity() { return LOGICAL_DENSITY; } diff --git a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java index 6373ff240..50f5d8f2e 100644 --- a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java +++ b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java @@ -31,7 +31,7 @@ import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.ChapterListAdapter; import de.danoeh.antennapod.adapter.NavListAdapter; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.dialog.VariableSpeedDialog; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.EventDistributor; @@ -381,8 +381,9 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc @Override public void run() { - ImageLoader.getInstance().loadThumbnailBitmap(media, - butNavLeft); + PicassoProvider.getMediaMetadataPicassoInstance(AudioplayerActivity.this) + .load(media.getImageUri()) + .into(butNavLeft); } }); butNavLeft.setContentDescription(getString(buttonTexts[2])); @@ -396,9 +397,11 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc @Override public void run() { - ImageLoader.getInstance().loadThumbnailBitmap(media, - butNavLeft); + PicassoProvider.getMediaMetadataPicassoInstance(AudioplayerActivity.this) + .load(media.getImageUri()) + .into(butNavLeft); } + }); butNavLeft.setContentDescription(getString(buttonTexts[2])); diff --git a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java index e89f8d05c..86b278bf0 100644 --- a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java +++ b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java @@ -9,11 +9,28 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; -import android.widget.*; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.Spinner; +import android.widget.TextView; + +import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.examples.HtmlToPlainText; +import org.jsoup.nodes.Document; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter; -import de.danoeh.antennapod.asynctask.ImageDiskCache; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.feed.Feed; @@ -21,15 +38,6 @@ import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; -import org.apache.commons.lang3.StringUtils; -import org.jsoup.Jsoup; -import org.jsoup.examples.HtmlToPlainText; -import org.jsoup.nodes.Document; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; /** * Default implementation of OnlineFeedViewActivity. Shows the downloaded feed's items with their descriptions, @@ -115,9 +123,13 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { subscribeButton = (Button) header.findViewById(R.id.butSubscribe); if (feed.getImage() != null) { - ImageDiskCache.getDefaultInstance().loadThumbnailBitmap(feed.getImage().getDownload_url(), cover, (int) getResources().getDimension( - R.dimen.thumbnail_length)); + int imageSize = (int) getResources().getDimension(R.dimen.thumbnail_length); + PicassoProvider.getDefaultPicassoInstance(this) + .load(feed.getImage().getDownload_url()) + .resize(imageSize, imageSize) + .into(cover); } + title.setText(feed.getTitle()); author.setText(feed.getAuthor()); description.setText(feed.getDescription()); diff --git a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java index 7f60d0b10..b46bc7546 100644 --- a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java +++ b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java @@ -12,7 +12,7 @@ import android.view.MenuItem; import android.widget.*; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.feed.FeedPreferences; @@ -78,8 +78,9 @@ public class FeedInfoActivity extends ActionBarActivity { @Override public void run() { - ImageLoader.getInstance().loadThumbnailBitmap( - feed.getImage(), imgvCover); + PicassoProvider.getDefaultPicassoInstance(FeedInfoActivity.this) + .load(feed.getImageUri()) + .into(imgvCover); } }); diff --git a/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java index 33b11774f..641a1368d 100644 --- a/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java @@ -9,8 +9,9 @@ import android.widget.BaseAdapter; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; + import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.util.Converter; @@ -22,10 +23,13 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { private final Context context; private final ItemAccess itemAccess; + private final int imageSize; + public DownloadedEpisodesListAdapter(Context context, ItemAccess itemAccess) { super(); this.context = context; this.itemAccess = itemAccess; + this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length_downloaded_item); } @Override @@ -83,12 +87,11 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { holder.butSecondary.setOnClickListener(secondaryActionListener); - ImageLoader.getInstance().loadThumbnailBitmap( - item, - holder.imageView, - (int) convertView.getResources().getDimension( - R.dimen.thumbnail_length) - ); + PicassoProvider.getMediaMetadataPicassoInstance(context) + .load(item.getImageUri()) + .resize(imageSize, imageSize) + .into(holder.imageView); + return convertView; } diff --git a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java index 5e857c131..56c3e1ca6 100644 --- a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java @@ -6,9 +6,14 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.*; +import android.widget.BaseExpandableListAdapter; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.storage.DownloadRequester; @@ -19,276 +24,282 @@ import de.danoeh.antennapod.util.Converter; * structure of this list is: [header] [queueItems] [header] [unreadItems]. */ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { - private static final String TAG = "ExternalEpisodesListAdapter"; + private static final String TAG = "ExternalEpisodesListAdapter"; - public static final int GROUP_POS_QUEUE = 0; - public static final int GROUP_POS_UNREAD = 1; + public static final int GROUP_POS_QUEUE = 0; + public static final int GROUP_POS_UNREAD = 1; - private Context context; + private Context context; private ItemAccess itemAccess; - private ActionButtonCallback feedItemActionCallback; - private OnGroupActionClicked groupActionCallback; + private ActionButtonCallback feedItemActionCallback; + private OnGroupActionClicked groupActionCallback; + + private final int imageSize; - public ExternalEpisodesListAdapter(Context context, - ActionButtonCallback callback, - OnGroupActionClicked groupActionCallback, - ItemAccess itemAccess) { - super(); - this.context = context; + public ExternalEpisodesListAdapter(Context context, + ActionButtonCallback callback, + OnGroupActionClicked groupActionCallback, + ItemAccess itemAccess) { + super(); + this.context = context; this.itemAccess = itemAccess; - this.feedItemActionCallback = callback; - this.groupActionCallback = groupActionCallback; - } - - @Override - public boolean areAllItemsEnabled() { - return true; - } - - @Override - public FeedItem getChild(int groupPosition, int childPosition) { - if (groupPosition == GROUP_POS_QUEUE) { - return itemAccess.getQueueItemAt(childPosition); - } else if (groupPosition == GROUP_POS_UNREAD) { + this.feedItemActionCallback = callback; + this.groupActionCallback = groupActionCallback; + this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length); + } + + @Override + public boolean areAllItemsEnabled() { + return true; + } + + @Override + public FeedItem getChild(int groupPosition, int childPosition) { + if (groupPosition == GROUP_POS_QUEUE) { + return itemAccess.getQueueItemAt(childPosition); + } else if (groupPosition == GROUP_POS_UNREAD) { return itemAccess.getUnreadItemAt(childPosition); - } - return null; - } - - @Override - public long getChildId(int groupPosition, int childPosition) { - return childPosition; - } - - @Override - public View getChildView(int groupPosition, final int childPosition, - boolean isLastChild, View convertView, ViewGroup parent) { - Holder holder; - final FeedItem item = getChild(groupPosition, childPosition); - - if (convertView == null) { - holder = new Holder(); - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.external_itemlist_item, - parent, false); - holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); - holder.feedTitle = (TextView) convertView - .findViewById(R.id.txtvFeedname); - holder.lenSize = (TextView) convertView - .findViewById(R.id.txtvLenSize); - holder.downloadStatus = (ImageView) convertView - .findViewById(R.id.imgvDownloadStatus); - holder.feedImage = (ImageView) convertView - .findViewById(R.id.imgvFeedimage); - holder.butAction = (ImageButton) convertView - .findViewById(R.id.butAction); - holder.statusPlaying = (View) convertView - .findViewById(R.id.statusPlaying); - holder.episodeProgress = (ProgressBar) convertView - .findViewById(R.id.pbar_episode_progress); - convertView.setTag(holder); - } else { - holder = (Holder) convertView.getTag(); - } - - holder.title.setText(item.getTitle()); - holder.feedTitle.setText(item.getFeed().getTitle()); - FeedItem.State state = item.getState(); - - if (groupPosition == GROUP_POS_QUEUE) { - switch (state) { - case PLAYING: - holder.statusPlaying.setVisibility(View.VISIBLE); - holder.episodeProgress.setVisibility(View.VISIBLE); - break; - case IN_PROGRESS: - holder.statusPlaying.setVisibility(View.GONE); - holder.episodeProgress.setVisibility(View.VISIBLE); - break; - case NEW: - holder.statusPlaying.setVisibility(View.GONE); - holder.episodeProgress.setVisibility(View.GONE); - break; - default: - holder.statusPlaying.setVisibility(View.GONE); - holder.episodeProgress.setVisibility(View.GONE); - break; - } - } else { - holder.statusPlaying.setVisibility(View.GONE); - holder.episodeProgress.setVisibility(View.GONE); - } - - FeedMedia media = item.getMedia(); - if (media != null) { - - if (state == FeedItem.State.PLAYING - || state == FeedItem.State.IN_PROGRESS) { - if (media.getDuration() > 0) { - holder.episodeProgress.setProgress((int) (((double) media - .getPosition()) / media.getDuration() * 100)); - holder.lenSize.setText(Converter - .getDurationStringLong(media.getDuration() - - media.getPosition())); - } - } else if (!media.isDownloaded()) { - holder.lenSize.setText(context.getString(R.string.size_prefix) - + Converter.byteToString(media.getSize())); - } else { - holder.lenSize.setText(context - .getString(R.string.length_prefix) - + Converter.getDurationStringLong(media.getDuration())); - } - - TypedArray drawables = context.obtainStyledAttributes(new int[] { - R.attr.av_download, R.attr.navigation_refresh }); - final int[] labels = new int[] {R.string.status_downloaded_label, R.string.downloading_label}; - holder.lenSize.setVisibility(View.VISIBLE); - if (!media.isDownloaded()) { - if (DownloadRequester.getInstance().isDownloadingFile(media)) { - holder.downloadStatus.setVisibility(View.VISIBLE); - holder.downloadStatus.setImageDrawable(drawables - .getDrawable(1)); + } + return null; + } + + @Override + public long getChildId(int groupPosition, int childPosition) { + return childPosition; + } + + @Override + public View getChildView(int groupPosition, final int childPosition, + boolean isLastChild, View convertView, ViewGroup parent) { + Holder holder; + final FeedItem item = getChild(groupPosition, childPosition); + + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.external_itemlist_item, + parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.feedTitle = (TextView) convertView + .findViewById(R.id.txtvFeedname); + holder.lenSize = (TextView) convertView + .findViewById(R.id.txtvLenSize); + holder.downloadStatus = (ImageView) convertView + .findViewById(R.id.imgvDownloadStatus); + holder.feedImage = (ImageView) convertView + .findViewById(R.id.imgvFeedimage); + holder.butAction = (ImageButton) convertView + .findViewById(R.id.butAction); + holder.statusPlaying = (View) convertView + .findViewById(R.id.statusPlaying); + holder.episodeProgress = (ProgressBar) convertView + .findViewById(R.id.pbar_episode_progress); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.title.setText(item.getTitle()); + holder.feedTitle.setText(item.getFeed().getTitle()); + FeedItem.State state = item.getState(); + + if (groupPosition == GROUP_POS_QUEUE) { + switch (state) { + case PLAYING: + holder.statusPlaying.setVisibility(View.VISIBLE); + holder.episodeProgress.setVisibility(View.VISIBLE); + break; + case IN_PROGRESS: + holder.statusPlaying.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.VISIBLE); + break; + case NEW: + holder.statusPlaying.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); + break; + default: + holder.statusPlaying.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); + break; + } + } else { + holder.statusPlaying.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); + } + + FeedMedia media = item.getMedia(); + if (media != null) { + + if (state == FeedItem.State.PLAYING + || state == FeedItem.State.IN_PROGRESS) { + if (media.getDuration() > 0) { + holder.episodeProgress.setProgress((int) (((double) media + .getPosition()) / media.getDuration() * 100)); + holder.lenSize.setText(Converter + .getDurationStringLong(media.getDuration() + - media.getPosition())); + } + } else if (!media.isDownloaded()) { + holder.lenSize.setText(context.getString(R.string.size_prefix) + + Converter.byteToString(media.getSize())); + } else { + holder.lenSize.setText(context + .getString(R.string.length_prefix) + + Converter.getDurationStringLong(media.getDuration())); + } + + TypedArray drawables = context.obtainStyledAttributes(new int[]{ + R.attr.av_download, R.attr.navigation_refresh}); + final int[] labels = new int[]{R.string.status_downloaded_label, R.string.downloading_label}; + holder.lenSize.setVisibility(View.VISIBLE); + if (!media.isDownloaded()) { + if (DownloadRequester.getInstance().isDownloadingFile(media)) { + holder.downloadStatus.setVisibility(View.VISIBLE); + holder.downloadStatus.setImageDrawable(drawables + .getDrawable(1)); holder.downloadStatus.setContentDescription(context.getString(labels[1])); - } else { - holder.downloadStatus.setVisibility(View.INVISIBLE); - } - } else { - holder.downloadStatus.setVisibility(View.VISIBLE); - holder.downloadStatus - .setImageDrawable(drawables.getDrawable(0)); + } else { + holder.downloadStatus.setVisibility(View.INVISIBLE); + } + } else { + holder.downloadStatus.setVisibility(View.VISIBLE); + holder.downloadStatus + .setImageDrawable(drawables.getDrawable(0)); holder.downloadStatus.setContentDescription(context.getString(labels[0])); - } - } else { - holder.downloadStatus.setVisibility(View.INVISIBLE); - holder.lenSize.setVisibility(View.INVISIBLE); - } - - ImageLoader.getInstance().loadThumbnailBitmap( - item, - holder.feedImage, - (int) convertView.getResources().getDimension( - R.dimen.thumbnail_length)); - holder.butAction.setFocusable(false); - holder.butAction.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - feedItemActionCallback.onActionButtonPressed(item); - } - }); - - return convertView; - - } - - static class Holder { - TextView title; - TextView feedTitle; - TextView lenSize; - ImageView downloadStatus; - ImageView feedImage; - ImageButton butAction; - View statusPlaying; - ProgressBar episodeProgress; - } - - @Override - public int getChildrenCount(int groupPosition) { - if (groupPosition == GROUP_POS_QUEUE) { - return itemAccess.getQueueSize(); - } else if (groupPosition == GROUP_POS_UNREAD) { - return itemAccess.getUnreadItemsSize(); - } - return 0; - } - - @Override - public int getGroupCount() { - // Hide 'unread items' group if empty - if (itemAccess.getUnreadItemsSize() > 0) { - return 2; - } else { - return 1; - } - } - - @Override - public long getGroupId(int groupPosition) { - return groupPosition; - } - - @Override - public View getGroupView(final int groupPosition, boolean isExpanded, - View convertView, ViewGroup parent) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.feeditemlist_header, parent, false); - TextView headerTitle = (TextView) convertView - .findViewById(0); - ImageButton actionButton = (ImageButton) convertView - .findViewById(R.id.butAction); - TextView numItems = (TextView) convertView.findViewById(0); - - String headerString = null; - int childrenCount = 0; - - if (groupPosition == 0) { - headerString = context.getString(R.string.queue_label); - childrenCount = getChildrenCount(GROUP_POS_QUEUE); - } else { - headerString = context.getString(R.string.waiting_list_label); - childrenCount = getChildrenCount(GROUP_POS_UNREAD); - } - headerTitle.setText(headerString); - if (childrenCount <= 0) { - numItems.setVisibility(View.INVISIBLE); - } else { - numItems.setVisibility(View.VISIBLE); - numItems.setText(Integer.toString(childrenCount)); - } - actionButton.setFocusable(false); - actionButton.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - groupActionCallback.onClick(getGroupId(groupPosition)); - } - }); - return convertView; - } - - @Override - public boolean isEmpty() { - return itemAccess.getUnreadItemsSize() == 0 - && itemAccess.getQueueSize() == 0; - } - - @Override - public Object getGroup(int groupPosition) { - return null; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public boolean isChildSelectable(int groupPosition, int childPosition) { - return true; - } - - public interface OnGroupActionClicked { - public void onClick(long groupId); - } + } + } else { + holder.downloadStatus.setVisibility(View.INVISIBLE); + holder.lenSize.setVisibility(View.INVISIBLE); + } + + PicassoProvider.getMediaMetadataPicassoInstance(context) + .load(item.getImageUri()) + .resize(imageSize, imageSize) + .into(holder.feedImage); + + holder.butAction.setFocusable(false); + holder.butAction.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + feedItemActionCallback.onActionButtonPressed(item); + } + }); + + return convertView; + + } + + static class Holder { + TextView title; + TextView feedTitle; + TextView lenSize; + ImageView downloadStatus; + ImageView feedImage; + ImageButton butAction; + View statusPlaying; + ProgressBar episodeProgress; + } + + @Override + public int getChildrenCount(int groupPosition) { + if (groupPosition == GROUP_POS_QUEUE) { + return itemAccess.getQueueSize(); + } else if (groupPosition == GROUP_POS_UNREAD) { + return itemAccess.getUnreadItemsSize(); + } + return 0; + } + + @Override + public int getGroupCount() { + // Hide 'unread items' group if empty + if (itemAccess.getUnreadItemsSize() > 0) { + return 2; + } else { + return 1; + } + } + + @Override + public long getGroupId(int groupPosition) { + return groupPosition; + } + + @Override + public View getGroupView(final int groupPosition, boolean isExpanded, + View convertView, ViewGroup parent) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.feeditemlist_header, parent, false); + TextView headerTitle = (TextView) convertView + .findViewById(0); + ImageButton actionButton = (ImageButton) convertView + .findViewById(R.id.butAction); + TextView numItems = (TextView) convertView.findViewById(0); + + String headerString = null; + int childrenCount = 0; + + if (groupPosition == 0) { + headerString = context.getString(R.string.queue_label); + childrenCount = getChildrenCount(GROUP_POS_QUEUE); + } else { + headerString = context.getString(R.string.waiting_list_label); + childrenCount = getChildrenCount(GROUP_POS_UNREAD); + } + headerTitle.setText(headerString); + if (childrenCount <= 0) { + numItems.setVisibility(View.INVISIBLE); + } else { + numItems.setVisibility(View.VISIBLE); + numItems.setText(Integer.toString(childrenCount)); + } + actionButton.setFocusable(false); + actionButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + groupActionCallback.onClick(getGroupId(groupPosition)); + } + }); + return convertView; + } + + @Override + public boolean isEmpty() { + return itemAccess.getUnreadItemsSize() == 0 + && itemAccess.getQueueSize() == 0; + } + + @Override + public Object getGroup(int groupPosition) { + return null; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public boolean isChildSelectable(int groupPosition, int childPosition) { + return true; + } + + public interface OnGroupActionClicked { + public void onClick(long groupId); + } public static interface ItemAccess { public int getQueueSize(); + public int getUnreadItemsSize(); + public FeedItem getQueueItemAt(int position); + public FeedItem getUnreadItemAt(int position); } diff --git a/src/de/danoeh/antennapod/adapter/NavListAdapter.java b/src/de/danoeh/antennapod/adapter/NavListAdapter.java index 9676372fb..ed85c8836 100644 --- a/src/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -11,7 +11,7 @@ import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.feed.Feed; /** @@ -32,6 +32,8 @@ public class NavListAdapter extends BaseAdapter { private ItemAccess itemAccess; private Context context; + private final int imageSize; + public NavListAdapter(ItemAccess itemAccess, Context context) { this.itemAccess = itemAccess; this.context = context; @@ -41,6 +43,7 @@ public class NavListAdapter extends BaseAdapter { drawables = new Drawable[]{ta.getDrawable(0), ta.getDrawable(1), ta.getDrawable(2), ta.getDrawable(3), ta.getDrawable(4)}; ta.recycle(); + this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length_navlist); } @Override @@ -189,7 +192,11 @@ public class NavListAdapter extends BaseAdapter { } holder.title.setText(feed.getTitle()); - ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(), holder.image, (int) context.getResources().getDimension(R.dimen.thumbnail_length_navlist)); + + PicassoProvider.getDefaultPicassoInstance(context) + .load(feed.getImageUri()) + .resize(imageSize, imageSize) + .into(holder.image); return convertView; } diff --git a/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java index 07fd3e6b1..4370de14d 100644 --- a/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java @@ -5,9 +5,14 @@ import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.*; +import android.widget.BaseAdapter; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.storage.DownloadRequester; @@ -22,6 +27,7 @@ public class NewEpisodesListAdapter extends BaseAdapter { private final ItemAccess itemAccess; private final ActionButtonCallback actionButtonCallback; private final ActionButtonUtils actionButtonUtils; + private final int imageSize; public NewEpisodesListAdapter(Context context, ItemAccess itemAccess, ActionButtonCallback actionButtonCallback) { super(); @@ -29,6 +35,7 @@ public class NewEpisodesListAdapter extends BaseAdapter { this.itemAccess = itemAccess; this.actionButtonUtils = new ActionButtonUtils(context); this.actionButtonCallback = actionButtonCallback; + this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length_itemlist); } @Override @@ -124,13 +131,11 @@ public class NewEpisodesListAdapter extends BaseAdapter { holder.butSecondary.setTag(item); holder.butSecondary.setOnClickListener(secondaryActionListener); + PicassoProvider.getMediaMetadataPicassoInstance(context) + .load(item.getImageUri()) + .resize(imageSize, imageSize) + .into(holder.imageView); - ImageLoader.getInstance().loadThumbnailBitmap( - item, - holder.imageView, - (int) convertView.getResources().getDimension( - R.dimen.thumbnail_length) - ); return convertView; } diff --git a/src/de/danoeh/antennapod/adapter/QueueListAdapter.java b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java index f671ba5c6..c670089b9 100644 --- a/src/de/danoeh/antennapod/adapter/QueueListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java @@ -6,7 +6,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.*; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.storage.DownloadRequester; @@ -22,12 +22,15 @@ public class QueueListAdapter extends BaseAdapter { private final ActionButtonCallback actionButtonCallback; private final ActionButtonUtils actionButtonUtils; + private final int imageSize; + public QueueListAdapter(Context context, ItemAccess itemAccess, ActionButtonCallback actionButtonCallback) { super(); this.context = context; this.itemAccess = itemAccess; this.actionButtonUtils = new ActionButtonUtils(context); this.actionButtonCallback = actionButtonCallback; + this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length_queue_item); } @@ -92,13 +95,11 @@ public class QueueListAdapter extends BaseAdapter { holder.butSecondary.setTag(item); holder.butSecondary.setOnClickListener(secondaryActionListener); + PicassoProvider.getMediaMetadataPicassoInstance(context) + .load(item.getImageUri()) + .resize(imageSize, imageSize) + .into(holder.imageView); - ImageLoader.getInstance().loadThumbnailBitmap( - item, - holder.imageView, - (int) convertView.getResources().getDimension( - R.dimen.thumbnail_length) - ); return convertView; } diff --git a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java index ecfbb4660..6b1fefaad 100644 --- a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java @@ -4,28 +4,31 @@ import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; + import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.feed.FeedComponent; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.SearchResult; -import java.util.List; - -/** List adapter for search activity. */ +/** + * List adapter for search activity. + */ public class SearchlistAdapter extends BaseAdapter { - private final Context context; + private final Context context; private final ItemAccess itemAccess; + private final int imageSize; + public SearchlistAdapter(Context context, ItemAccess itemAccess) { this.context = context; this.itemAccess = itemAccess; + this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length); } @Override @@ -44,61 +47,65 @@ public class SearchlistAdapter extends BaseAdapter { } @Override - public View getView(int position, View convertView, ViewGroup parent) { - final Holder holder; - SearchResult result = getItem(position); - FeedComponent component = result.getComponent(); - - // Inflate Layout - if (convertView == null) { - holder = new Holder(); - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - convertView = inflater.inflate(R.layout.searchlist_item, parent, false); - holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); - holder.cover = (ImageView) convertView - .findViewById(R.id.imgvFeedimage); - holder.subtitle = (TextView) convertView - .findViewById(R.id.txtvSubtitle); - - convertView.setTag(holder); - } else { - holder = (Holder) convertView.getTag(); - } - if (component.getClass() == Feed.class) { - final Feed feed = (Feed) component; - holder.title.setText(feed.getTitle()); - holder.subtitle.setVisibility(View.GONE); - ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(), - holder.cover, (int) convertView.getResources().getDimension(R.dimen.thumbnail_length)); - } else if (component.getClass() == FeedItem.class) { - final FeedItem item = (FeedItem) component; - holder.title.setText(item.getTitle()); - if (result.getSubtitle() != null) { - holder.subtitle.setVisibility(View.VISIBLE); - holder.subtitle.setText(result.getSubtitle()); - } - - ImageLoader.getInstance().loadThumbnailBitmap( - item.getFeed().getImage(), - holder.cover, - (int) convertView.getResources().getDimension( - R.dimen.thumbnail_length)); - - } - - return convertView; - } - - static class Holder { - ImageView cover; - TextView title; - TextView subtitle; - } + public View getView(int position, View convertView, ViewGroup parent) { + final Holder holder; + SearchResult result = getItem(position); + FeedComponent component = result.getComponent(); + + // Inflate Layout + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.searchlist_item, parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.cover = (ImageView) convertView + .findViewById(R.id.imgvFeedimage); + holder.subtitle = (TextView) convertView + .findViewById(R.id.txtvSubtitle); + + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + if (component.getClass() == Feed.class) { + final Feed feed = (Feed) component; + holder.title.setText(feed.getTitle()); + holder.subtitle.setVisibility(View.GONE); + + PicassoProvider.getDefaultPicassoInstance(context) + .load(feed.getImageUri()) + .resize(imageSize, imageSize) + .into(holder.cover); + + } else if (component.getClass() == FeedItem.class) { + final FeedItem item = (FeedItem) component; + holder.title.setText(item.getTitle()); + if (result.getSubtitle() != null) { + holder.subtitle.setVisibility(View.VISIBLE); + holder.subtitle.setText(result.getSubtitle()); + } + + PicassoProvider.getDefaultPicassoInstance(context) + .load(item.getFeed().getImageUri()) + .resize(imageSize, imageSize) + .into(holder.cover); + + } + + return convertView; + } + + static class Holder { + ImageView cover; + TextView title; + TextView subtitle; + } public static interface ItemAccess { int getCount(); + SearchResult getItem(int position); } diff --git a/src/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java b/src/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java index f20232a6f..dcad2d524 100644 --- a/src/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java @@ -7,22 +7,21 @@ import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageDiskCache; -import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast; import java.util.List; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.asynctask.PicassoProvider; +import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast; + /** * Adapter for displaying a list of GPodnetPodcast-Objects. */ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> { - private final ImageDiskCache diskCache; private final int thumbnailLength; public PodcastListAdapter(Context context, int resource, List<GpodnetPodcast> objects) { super(context, resource, objects); - diskCache = ImageDiskCache.getDefaultInstance(); thumbnailLength = (int) context.getResources().getDimension(R.dimen.thumbnail_length); } @@ -50,7 +49,11 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> { holder.title.setText(podcast.getTitle()); holder.description.setText(podcast.getDescription()); - diskCache.loadThumbnailBitmap(podcast.getLogoUrl(), holder.image, thumbnailLength); + + PicassoProvider.getDefaultPicassoInstance(convertView.getContext()) + .load(podcast.getLogoUrl()) + .resize(thumbnailLength, thumbnailLength) + .into(holder.image); return convertView; } diff --git a/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java b/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java deleted file mode 100644 index 43118c3af..000000000 --- a/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java +++ /dev/null @@ -1,115 +0,0 @@ -package de.danoeh.antennapod.asynctask; - -import android.graphics.BitmapFactory; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.TransitionDrawable; -import android.os.Handler; -import android.util.Log; -import android.widget.ImageView; -import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.PodcastApp; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader.ImageWorkerTaskResource; -import de.danoeh.antennapod.util.BitmapDecoder; - -public class BitmapDecodeWorkerTask extends Thread { - - protected int PREFERRED_LENGTH; - public static final int FADE_DURATION = 500; - - /** - * Can be thumbnail or cover - */ - protected int imageType; - - private static final String TAG = "BitmapDecodeWorkerTask"; - private ImageView target; - protected CachedBitmap cBitmap; - - protected ImageLoader.ImageWorkerTaskResource imageResource; - - private Handler handler; - - private final int defaultCoverResource; - - public BitmapDecodeWorkerTask(Handler handler, ImageView target, - ImageWorkerTaskResource imageResource, int length, int imageType) { - super(); - this.handler = handler; - this.target = target; - this.imageResource = imageResource; - this.PREFERRED_LENGTH = length; - this.imageType = imageType; - this.defaultCoverResource = android.R.color.transparent; - } - - /** - * Should return true if tag of the imageview is still the same it was - * before the bitmap was decoded - */ - protected boolean tagsMatching(ImageView target) { - Object tag = target.getTag(R.id.imageloader_key); - return tag != null && tag.equals(imageResource.getImageLoaderCacheKey()); - } - - protected void onPostExecute() { - // check if imageview is still supposed to display this image - if (tagsMatching(target) && cBitmap.getBitmap() != null) { - Drawable[] drawables = new Drawable[]{ - PodcastApp.getInstance().getResources().getDrawable(android.R.color.transparent), - new BitmapDrawable(PodcastApp.getInstance().getResources(), cBitmap.getBitmap()) - }; - TransitionDrawable transitionDrawable = new TransitionDrawable(drawables); - target.setImageDrawable(transitionDrawable); - transitionDrawable.startTransition(FADE_DURATION); - } else { - if (BuildConfig.DEBUG) - Log.d(TAG, "Not displaying image"); - } - } - - @Override - public void run() { - cBitmap = new CachedBitmap(BitmapDecoder.decodeBitmapFromWorkerTaskResource( - PREFERRED_LENGTH, imageResource), PREFERRED_LENGTH); - if (cBitmap.getBitmap() != null) { - storeBitmapInCache(cBitmap); - } else { - Log.w(TAG, "Could not load bitmap. Using default image."); - cBitmap = new CachedBitmap(BitmapFactory.decodeResource( - target.getResources(), defaultCoverResource), - PREFERRED_LENGTH); - } - if (BuildConfig.DEBUG) - Log.d(TAG, "Finished loading bitmaps"); - - endBackgroundTask(); - } - - protected final void endBackgroundTask() { - handler.post(new Runnable() { - - @Override - public void run() { - onPostExecute(); - } - - }); - } - - protected void onInvalidStream() { - cBitmap = new CachedBitmap(BitmapFactory.decodeResource( - target.getResources(), defaultCoverResource), PREFERRED_LENGTH); - } - - protected void storeBitmapInCache(CachedBitmap cb) { - ImageLoader loader = ImageLoader.getInstance(); - if (imageType == ImageLoader.IMAGE_TYPE_COVER) { - loader.addBitmapToCoverCache(imageResource.getImageLoaderCacheKey(), cb); - } else if (imageType == ImageLoader.IMAGE_TYPE_THUMBNAIL) { - loader.addBitmapToThumbnailCache(imageResource.getImageLoaderCacheKey(), cb); - } - } - -} diff --git a/src/de/danoeh/antennapod/asynctask/CachedBitmap.java b/src/de/danoeh/antennapod/asynctask/CachedBitmap.java deleted file mode 100644 index 5a89b7b53..000000000 --- a/src/de/danoeh/antennapod/asynctask/CachedBitmap.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.danoeh.antennapod.asynctask; - -import android.graphics.Bitmap; - -/** Stores a bitmap and the length it was decoded with. */ -public class CachedBitmap { - - private Bitmap bitmap; - private int length; - - public CachedBitmap(Bitmap bitmap, int length) { - super(); - this.bitmap = bitmap; - this.length = length; - } - - public Bitmap getBitmap() { - return bitmap; - } - public int getLength() { - return length; - } - - - - -} diff --git a/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java b/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java deleted file mode 100644 index 77609f28b..000000000 --- a/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java +++ /dev/null @@ -1,397 +0,0 @@ -package de.danoeh.antennapod.asynctask; - -import android.os.Handler; -import android.util.Log; -import android.util.Pair; -import android.widget.ImageView; -import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.PodcastApp; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.service.download.DownloadRequest; -import de.danoeh.antennapod.service.download.HttpDownloader; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; - -import java.io.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * Provides local cache for storing downloaded image. An image disk cache downloads images and stores them as long - * as the cache is not full. Once the cache is full, the image disk cache will delete older images. - */ -public class ImageDiskCache { - private static final String TAG = "ImageDiskCache"; - - private static HashMap<String, ImageDiskCache> cacheSingletons = new HashMap<String, ImageDiskCache>(); - - /** - * Return a default instance of an ImageDiskCache. This cache will store data in the external cache folder. - */ - public static synchronized ImageDiskCache getDefaultInstance() { - final String DEFAULT_PATH = "imagecache"; - final long DEFAULT_MAX_CACHE_SIZE = 10 * 1024 * 1024; - - File cacheDir = PodcastApp.getInstance().getExternalCacheDir(); - if (cacheDir == null) { - return null; - } - return getInstance(new File(cacheDir, DEFAULT_PATH).getAbsolutePath(), DEFAULT_MAX_CACHE_SIZE); - } - - /** - * Return an instance of an ImageDiskCache that stores images in the specified folder. - */ - public static synchronized ImageDiskCache getInstance(String path, long maxCacheSize) { - Validate.notNull(path); - - if (cacheSingletons.containsKey(path)) { - return cacheSingletons.get(path); - } - - ImageDiskCache cache = cacheSingletons.get(path); - if (cache == null) { - cache = new ImageDiskCache(path, maxCacheSize); - cacheSingletons.put(new File(path).getAbsolutePath(), cache); - } - cacheSingletons.put(path, cache); - return cache; - } - - /** - * Filename - cache object mapping - */ - private static final String CACHE_FILE_NAME = "cachefile"; - private ExecutorService executor; - private ConcurrentHashMap<String, DiskCacheObject> diskCache; - private final long maxCacheSize; - private int cacheSize; - private final File cacheFolder; - private Handler handler; - - private ImageDiskCache(String path, long maxCacheSize) { - this.maxCacheSize = maxCacheSize; - this.cacheFolder = new File(path); - if (!cacheFolder.exists() && !cacheFolder.mkdir()) { - throw new IllegalArgumentException("Image disk cache could not create cache folder in: " + path); - } - - executor = Executors.newFixedThreadPool(Runtime.getRuntime() - .availableProcessors()); - handler = new Handler(); - } - - private synchronized void initCacheFolder() { - if (diskCache == null) { - if (BuildConfig.DEBUG) Log.d(TAG, "Initializing cache folder"); - File cacheFile = new File(cacheFolder, CACHE_FILE_NAME); - if (cacheFile.exists()) { - try { - InputStream in = new FileInputStream(cacheFile); - BufferedInputStream buffer = new BufferedInputStream(in); - ObjectInputStream objectInput = new ObjectInputStream(buffer); - diskCache = (ConcurrentHashMap<String, DiskCacheObject>) objectInput.readObject(); - // calculate cache size - for (DiskCacheObject dco : diskCache.values()) { - cacheSize += dco.size; - } - deleteInvalidFiles(); - } catch (IOException e) { - e.printStackTrace(); - diskCache = new ConcurrentHashMap<String, DiskCacheObject>(); - } catch (ClassCastException e) { - e.printStackTrace(); - diskCache = new ConcurrentHashMap<String, DiskCacheObject>(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - diskCache = new ConcurrentHashMap<String, DiskCacheObject>(); - } - } else { - diskCache = new ConcurrentHashMap<String, DiskCacheObject>(); - } - } - } - - private List<File> getCacheFileList() { - Collection<DiskCacheObject> values = diskCache.values(); - List<File> files = new ArrayList<File>(); - for (DiskCacheObject dco : values) { - files.add(dco.getFile()); - } - files.add(new File(cacheFolder, CACHE_FILE_NAME)); - return files; - } - - private Pair<String, DiskCacheObject> getOldestCacheObject() { - Collection<String> keys = diskCache.keySet(); - DiskCacheObject oldest = null; - String oldestKey = null; - - for (String key : keys) { - - if (oldestKey == null) { - oldestKey = key; - oldest = diskCache.get(key); - } else { - DiskCacheObject dco = diskCache.get(key); - if (oldest.timestamp > dco.timestamp) { - oldestKey = key; - oldest = diskCache.get(key); - } - } - } - return new Pair<String, DiskCacheObject>(oldestKey, oldest); - } - - private synchronized void deleteCacheObject(String key, DiskCacheObject value) { - Log.i(TAG, "Deleting cached object: " + key); - diskCache.remove(key); - boolean result = value.getFile().delete(); - if (!result) { - Log.w(TAG, "Could not delete file " + value.fileUrl); - } - cacheSize -= value.size; - } - - private synchronized void deleteInvalidFiles() { - // delete files that are not stored inside the cache - File[] files = cacheFolder.listFiles(); - List<File> cacheFiles = getCacheFileList(); - for (File file : files) { - if (!cacheFiles.contains(file)) { - Log.i(TAG, "Deleting unused file: " + file.getAbsolutePath()); - boolean result = file.delete(); - if (!result) { - Log.w(TAG, "Could not delete file: " + file.getAbsolutePath()); - } - } - } - } - - private synchronized void cleanup() { - if (cacheSize > maxCacheSize) { - while (cacheSize > maxCacheSize) { - Pair<String, DiskCacheObject> oldest = getOldestCacheObject(); - deleteCacheObject(oldest.first, oldest.second); - } - } - } - - /** - * Loads a new image from the disk cache. If the image that the url points to has already been downloaded, the image will - * be loaded from the disk. Otherwise, the image will be downloaded first. - * The image will be stored in the thumbnail cache. - */ - public void loadThumbnailBitmap(final String url, final ImageView target, final int length) { - if (url == null) { - Log.w(TAG, "loadThumbnailBitmap: Call was ignored because url = null"); - return; - } - final ImageLoader il = ImageLoader.getInstance(); - target.setTag(R.id.image_disk_cache_key, url); - if (diskCache != null) { - DiskCacheObject dco = getFromCacheIfAvailable(url); - if (dco != null) { - il.loadThumbnailBitmap(dco.loadImage(), target, length); - return; - } - } - target.setImageResource(android.R.color.transparent); - executor.submit(new ImageDownloader(url) { - @Override - protected void onImageLoaded(DiskCacheObject diskCacheObject) { - final Object tag = target.getTag(R.id.image_disk_cache_key); - if (tag != null && StringUtils.equals((String) tag, url)) { - il.loadThumbnailBitmap(diskCacheObject.loadImage(), target, length); - } - } - }); - - } - - /** - * Loads a new image from the disk cache. If the image that the url points to has already been downloaded, the image will - * be loaded from the disk. Otherwise, the image will be downloaded first. - * The image will be stored in the cover cache. - */ - public void loadCoverBitmap(final String url, final ImageView target, final int length) { - if (url == null) { - Log.w(TAG, "loadCoverBitmap: Call was ignored because url = null"); - return; - } - final ImageLoader il = ImageLoader.getInstance(); - target.setTag(R.id.image_disk_cache_key, url); - if (diskCache != null) { - DiskCacheObject dco = getFromCacheIfAvailable(url); - if (dco != null) { - il.loadThumbnailBitmap(dco.loadImage(), target, length); - return; - } - } - target.setImageResource(android.R.color.transparent); - executor.submit(new ImageDownloader(url) { - @Override - protected void onImageLoaded(DiskCacheObject diskCacheObject) { - final Object tag = target.getTag(R.id.image_disk_cache_key); - if (tag != null && StringUtils.equals((String) tag, url)) { - il.loadCoverBitmap(diskCacheObject.loadImage(), target, length); - } - } - }); - } - - private synchronized void addToDiskCache(String url, DiskCacheObject obj) { - if (diskCache == null) { - initCacheFolder(); - } - if (BuildConfig.DEBUG) Log.d(TAG, "Adding new image to disk cache: " + url); - diskCache.put(url, obj); - cacheSize += obj.size; - if (cacheSize > maxCacheSize) { - cleanup(); - } - saveCacheInfoFile(); - } - - private synchronized void saveCacheInfoFile() { - OutputStream out = null; - try { - out = new BufferedOutputStream(new FileOutputStream(new File(cacheFolder, CACHE_FILE_NAME))); - ObjectOutputStream objOut = new ObjectOutputStream(out); - objOut.writeObject(diskCache); - } catch (IOException e) { - e.printStackTrace(); - } finally { - IOUtils.closeQuietly(out); - } - } - - private synchronized DiskCacheObject getFromCacheIfAvailable(String key) { - if (diskCache == null) { - initCacheFolder(); - } - DiskCacheObject dco = diskCache.get(key); - if (dco != null) { - dco.timestamp = System.currentTimeMillis(); - } - return dco; - } - - ConcurrentHashMap<String, File> runningDownloads = new ConcurrentHashMap<String, File>(); - - private abstract class ImageDownloader implements Runnable { - private String downloadUrl; - - public ImageDownloader(String downloadUrl) { - this.downloadUrl = downloadUrl; - } - - protected abstract void onImageLoaded(DiskCacheObject diskCacheObject); - - public void run() { - DiskCacheObject tmp = getFromCacheIfAvailable(downloadUrl); - if (tmp != null) { - onImageLoaded(tmp); - return; - } - - DiskCacheObject dco = null; - File newFile = new File(cacheFolder, Integer.toString(downloadUrl.hashCode())); - synchronized (ImageDiskCache.this) { - if (runningDownloads.containsKey(newFile.getAbsolutePath())) { - Log.d(TAG, "Download is already running: " + newFile.getAbsolutePath()); - return; - } else { - runningDownloads.put(newFile.getAbsolutePath(), newFile); - } - } - if (newFile.exists()) { - newFile.delete(); - } - - HttpDownloader result = downloadFile(newFile.getAbsolutePath(), downloadUrl); - if (result.getResult().isSuccessful()) { - long size = result.getDownloadRequest().getSoFar(); - - dco = new DiskCacheObject(newFile.getAbsolutePath(), size); - addToDiskCache(downloadUrl, dco); - if (BuildConfig.DEBUG) Log.d(TAG, "Image was downloaded"); - } else { - Log.w(TAG, "Download of url " + downloadUrl + " failed. Reason: " + result.getResult().getReasonDetailed() + "(" + result.getResult().getReason() + ")"); - } - - if (dco != null) { - final DiskCacheObject dcoRef = dco; - handler.post(new Runnable() { - @Override - public void run() { - onImageLoaded(dcoRef); - } - }); - - } - runningDownloads.remove(newFile.getAbsolutePath()); - - } - - private HttpDownloader downloadFile(String destination, String source) { - DownloadRequest request = new DownloadRequest(destination, source, "", 0, 0); - HttpDownloader downloader = new HttpDownloader(request); - downloader.call(); - return downloader; - } - } - - private static class DiskCacheObject implements Serializable { - private final String fileUrl; - - /** - * Last usage of this image cache object. - */ - private long timestamp; - private final long size; - - public DiskCacheObject(String fileUrl, long size) { - Validate.notNull(fileUrl); - this.fileUrl = fileUrl; - this.timestamp = System.currentTimeMillis(); - this.size = size; - } - - public File getFile() { - return new File(fileUrl); - } - - public ImageLoader.ImageWorkerTaskResource loadImage() { - return new ImageLoader.ImageWorkerTaskResource() { - - @Override - public InputStream openImageInputStream() { - try { - return new FileInputStream(getFile()); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - return null; - } - - @Override - public InputStream reopenImageInputStream(InputStream input) { - IOUtils.closeQuietly(input); - return openImageInputStream(); - } - - @Override - public String getImageLoaderCacheKey() { - return fileUrl; - } - }; - } - } -} diff --git a/src/de/danoeh/antennapod/asynctask/ImageLoader.java b/src/de/danoeh/antennapod/asynctask/ImageLoader.java deleted file mode 100644 index 6c60b7b1f..000000000 --- a/src/de/danoeh/antennapod/asynctask/ImageLoader.java +++ /dev/null @@ -1,246 +0,0 @@ -package de.danoeh.antennapod.asynctask; - -import android.annotation.SuppressLint; -import android.app.ActivityManager; -import android.content.Context; -import android.os.Handler; -import android.support.v4.util.LruCache; -import android.util.Log; -import android.widget.ImageView; -import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.PodcastApp; -import de.danoeh.antennapod.R; - -import java.io.InputStream; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; - -/** - * Caches and loads FeedImage bitmaps in the background - */ -public class ImageLoader { - private static final String TAG = "ImageLoader"; - private static ImageLoader singleton; - - public static final int IMAGE_TYPE_THUMBNAIL = 0; - public static final int IMAGE_TYPE_COVER = 1; - - /** - * Used by loadThumbnailBitmap and loadCoverBitmap to denote an ImageView that displays the default image resource. - * This is the case if the given source to load the image from was null or did not return any image data. - */ - private static final Object DEFAULT_IMAGE_RESOURCE_TAG = new Object(); - - private Handler handler; - private ExecutorService executor; - - /** - * Stores references to loaded bitmaps. Bitmaps can be accessed by the id of - * the FeedImage the bitmap belongs to. - */ - - final int memClass = ((ActivityManager) PodcastApp.getInstance() - .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass(); - - // Use 1/8th of the available memory for this memory cache. - final int thumbnailCacheSize = 1024 * 1024 * memClass / 8; - - private LruCache<String, CachedBitmap> coverCache; - private LruCache<String, CachedBitmap> thumbnailCache; - - private ImageLoader() { - handler = new Handler(); - executor = createExecutor(); - - coverCache = new LruCache<String, CachedBitmap>(1); - - thumbnailCache = new LruCache<String, CachedBitmap>(thumbnailCacheSize) { - - @SuppressLint("NewApi") - @Override - protected int sizeOf(String key, CachedBitmap value) { - if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12) - return value.getBitmap().getByteCount(); - else - return (value.getBitmap().getRowBytes() * value.getBitmap() - .getHeight()); - - } - - }; - } - - private ExecutorService createExecutor() { - return Executors.newFixedThreadPool(Runtime.getRuntime() - .availableProcessors(), new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } - }); - } - - public static synchronized ImageLoader getInstance() { - if (singleton == null) { - singleton = new ImageLoader(); - } - return singleton; - } - - /** - * Load a bitmap from the cover cache. If the bitmap is not in the cache, it - * will be loaded from the disk. This method should either be called if the - * ImageView's size has already been set or inside a Runnable which is - * posted to the ImageView's message queue. - */ - public void loadCoverBitmap(ImageWorkerTaskResource source, ImageView target) { - loadCoverBitmap(source, target, target.getHeight()); - } - - /** - * Load a bitmap from the cover cache. If the bitmap is not in the cache, it - * will be loaded from the disk. This method should either be called if the - * ImageView's size has already been set or inside a Runnable which is - * posted to the ImageView's message queue. - */ - public void loadCoverBitmap(ImageWorkerTaskResource source, - ImageView target, int length) { - final int defaultCoverResource = getDefaultCoverResource(target - .getContext()); - final String cacheKey; - if (source != null && (cacheKey = source.getImageLoaderCacheKey()) != null) { - final Object currentTag = target.getTag(R.id.imageloader_key); - if (currentTag == null || !cacheKey.equals(currentTag)) { - target.setTag(R.id.imageloader_key, cacheKey); - CachedBitmap cBitmap = getBitmapFromCoverCache(cacheKey); - if (cBitmap != null && cBitmap.getLength() >= length) { - target.setImageBitmap(cBitmap.getBitmap()); - } else { - target.setImageResource(defaultCoverResource); - BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask( - handler, target, source, length, IMAGE_TYPE_COVER); - executor.submit(worker); - } - } - } else { - target.setImageResource(defaultCoverResource); - target.setTag(R.id.imageloader_key, DEFAULT_IMAGE_RESOURCE_TAG); - } - } - - /** - * Load a bitmap from the thumbnail cache. If the bitmap is not in the - * cache, it will be loaded from the disk. This method should either be - * called if the ImageView's size has already been set or inside a Runnable - * which is posted to the ImageView's message queue. - */ - public void loadThumbnailBitmap(ImageWorkerTaskResource source, - ImageView target) { - loadThumbnailBitmap(source, target, target.getHeight()); - } - - /** - * Load a bitmap from the thumbnail cache. If the bitmap is not in the - * cache, it will be loaded from the disk. This method should either be - * called if the ImageView's size has already been set or inside a Runnable - * which is posted to the ImageView's message queue. - */ - public void loadThumbnailBitmap(ImageWorkerTaskResource source, - ImageView target, int length) { - final int defaultCoverResource = getDefaultCoverResource(target - .getContext()); - final String cacheKey; - if (source != null && (cacheKey = source.getImageLoaderCacheKey()) != null) { - final Object currentTag = target.getTag(R.id.imageloader_key); - if (currentTag == null || !cacheKey.equals(currentTag)) { - target.setTag(R.id.imageloader_key, cacheKey); - CachedBitmap cBitmap = getBitmapFromThumbnailCache(cacheKey); - if (cBitmap != null && cBitmap.getLength() >= length) { - target.setImageBitmap(cBitmap.getBitmap()); - } else { - target.setImageResource(defaultCoverResource); - BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask( - handler, target, source, length, IMAGE_TYPE_THUMBNAIL); - executor.submit(worker); - } - } - } else { - target.setImageResource(defaultCoverResource); - target.setTag(R.id.imageloader_key, DEFAULT_IMAGE_RESOURCE_TAG); - } - } - - public void clearExecutorQueue() { - executor.shutdownNow(); - if (BuildConfig.DEBUG) - Log.d(TAG, "Executor was shut down."); - executor = createExecutor(); - - } - - public void wipeImageCache() { - coverCache.evictAll(); - thumbnailCache.evictAll(); - } - - public boolean isInThumbnailCache(String fileUrl) { - return thumbnailCache.get(fileUrl) != null; - } - - private CachedBitmap getBitmapFromThumbnailCache(String key) { - return thumbnailCache.get(key); - } - - public void addBitmapToThumbnailCache(String key, CachedBitmap bitmap) { - thumbnailCache.put(key, bitmap); - } - - public boolean isInCoverCache(String fileUrl) { - return coverCache.get(fileUrl) != null; - } - - private CachedBitmap getBitmapFromCoverCache(String key) { - return coverCache.get(key); - } - - public void addBitmapToCoverCache(String key, CachedBitmap bitmap) { - coverCache.put(key, bitmap); - } - - private int getDefaultCoverResource(Context context) { - return android.R.color.transparent; - } - - /** - * Used by the BitmapDecodeWorker task to retrieve the source of the bitmap. - */ - public interface ImageWorkerTaskResource { - /** - * Opens a new InputStream that can be decoded as a bitmap by the - * BitmapFactory. - */ - public InputStream openImageInputStream(); - - /** - * Returns an InputStream that points to the beginning of the image - * resource. Implementations can either create a new InputStream or - * reset the existing one, depending on their implementation of - * openInputStream. If a new InputStream is returned, the one given as a - * parameter MUST be closed. - * - * @param input The input stream that was returned by openImageInputStream() - */ - public InputStream reopenImageInputStream(InputStream input); - - /** - * Returns a string that identifies the image resource. Example: file - * path of an image - */ - public String getImageLoaderCacheKey(); - } - -} diff --git a/src/de/danoeh/antennapod/asynctask/PicassoImageResource.java b/src/de/danoeh/antennapod/asynctask/PicassoImageResource.java new file mode 100644 index 000000000..84179cfcb --- /dev/null +++ b/src/de/danoeh/antennapod/asynctask/PicassoImageResource.java @@ -0,0 +1,25 @@ +package de.danoeh.antennapod.asynctask; + +import android.net.Uri; + +/** + * Classes that implement this interface provide access to an image resource that can + * be loaded by the Picasso library. + */ +public interface PicassoImageResource { + + /** + * This scheme should be used by PicassoImageResources to + * indicate that the image Uri points to a file that is not an image + * (e.g. a media file). This workaround is needed so that the Picasso library + * loads these Uri with a Downloader instead of trying to load it directly. + * <p/> + * For example implementations, see FeedMedia or ExternalMedia. + */ + public static final String SCHEME_MEDIA = "media"; + + /** + * Returns a Uri to the image or null if no image is available. + */ + public Uri getImageUri(); +} diff --git a/src/de/danoeh/antennapod/asynctask/PicassoProvider.java b/src/de/danoeh/antennapod/asynctask/PicassoProvider.java new file mode 100644 index 000000000..fe70a9343 --- /dev/null +++ b/src/de/danoeh/antennapod/asynctask/PicassoProvider.java @@ -0,0 +1,137 @@ +package de.danoeh.antennapod.asynctask; + +import android.content.Context; +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 org.apache.commons.io.FilenameUtils; +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.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Provides access to Picasso instances. + */ +public class PicassoProvider { + private static final String TAG = "PicassoProvider"; + + private static final boolean DEBUG = false; + + 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); + } + return executorService; + } + + private static synchronized Cache getMemoryCache(Context context) { + if (memoryCache == null) { + memoryCache = new LruCache(context); + } + 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; + } + + /** + * 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(); + } + return mediaMetadataPicassoInstance; + } + + private static class MediaMetadataDownloader implements Downloader { + + private static final String TAG = "MediaMetadataDownloader"; + + private final OkHttpDownloader okHttpDownloader; + + public MediaMetadataDownloader(Context context) { + Validate.notNull(context); + okHttpDownloader = new OkHttpDownloader(context); + } + + @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()); + } else { + MediaMetadataRetriever mmr = new MediaMetadataRetriever(); + mmr.setDataSource(uri.getPath()); + byte[] data = mmr.getEmbeddedPicture(); + mmr.release(); + return new Response(new ByteArrayInputStream(data), true, data.length); + } + } + + return okHttpDownloader.load(uri, b); + } + } +} diff --git a/src/de/danoeh/antennapod/feed/Feed.java b/src/de/danoeh/antennapod/feed/Feed.java index f9da65e03..b5415c69c 100644 --- a/src/de/danoeh/antennapod/feed/Feed.java +++ b/src/de/danoeh/antennapod/feed/Feed.java @@ -1,6 +1,9 @@ package de.danoeh.antennapod.feed; import android.content.Context; +import android.net.Uri; + +import de.danoeh.antennapod.asynctask.PicassoImageResource; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.storage.DBWriter; import de.danoeh.antennapod.util.EpisodeFilter; @@ -16,7 +19,7 @@ import java.util.List; * * @author daniel */ -public class Feed extends FeedFile implements FlattrThing { +public class Feed extends FeedFile implements FlattrThing, PicassoImageResource { public static final int FEEDFILETYPE_FEED = 0; public static final String TYPE_RSS2 = "rss"; public static final String TYPE_RSS091 = "rss"; @@ -430,4 +433,13 @@ public class Feed extends FeedFile implements FlattrThing { preferences.setFeedID(id); } } + + @Override + public Uri getImageUri() { + if (image != null) { + return image.getImageUri(); + } else { + return null; + } + } } diff --git a/src/de/danoeh/antennapod/feed/FeedImage.java b/src/de/danoeh/antennapod/feed/FeedImage.java index 9c9170294..c588f5e71 100644 --- a/src/de/danoeh/antennapod/feed/FeedImage.java +++ b/src/de/danoeh/antennapod/feed/FeedImage.java @@ -1,6 +1,9 @@ package de.danoeh.antennapod.feed; -import de.danoeh.antennapod.asynctask.ImageLoader; +import android.net.Uri; + +import de.danoeh.antennapod.asynctask.PicassoImageResource; + import org.apache.commons.io.IOUtils; import java.io.File; @@ -10,8 +13,7 @@ import java.io.InputStream; -public class FeedImage extends FeedFile implements - ImageLoader.ImageWorkerTaskResource { +public class FeedImage extends FeedFile implements PicassoImageResource { public static final int FEEDFILETYPE_FEEDIMAGE = 1; protected String title; @@ -64,30 +66,12 @@ public class FeedImage extends FeedFile implements this.owner = owner; } - @Override - public InputStream openImageInputStream() { - if (file_url != null) { - File file = new File(file_url); - if (file.exists()) { - try { - return new FileInputStream(file_url); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - } - return null; - } - - @Override - public String getImageLoaderCacheKey() { - return file_url; - } - - @Override - public InputStream reopenImageInputStream(InputStream input) { - IOUtils.closeQuietly(input); - return openImageInputStream(); - } - + @Override + public Uri getImageUri() { + if (file_url != null && downloaded) { + return Uri.fromFile(new File(file_url)); + } else { + return null; + } + } } diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java index 956131ab2..78091ea33 100644 --- a/src/de/danoeh/antennapod/feed/FeedItem.java +++ b/src/de/danoeh/antennapod/feed/FeedItem.java @@ -1,7 +1,9 @@ package de.danoeh.antennapod.feed; +import android.net.Uri; + import de.danoeh.antennapod.PodcastApp; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoImageResource; import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.util.ShownotesProvider; import de.danoeh.antennapod.util.flattr.FlattrStatus; @@ -17,8 +19,7 @@ import java.util.concurrent.Callable; * * @author daniel */ -public class FeedItem extends FeedComponent implements - ImageLoader.ImageWorkerTaskResource, ShownotesProvider, FlattrThing { +public class FeedItem extends FeedComponent implements ShownotesProvider, FlattrThing, PicassoImageResource { /** * The id/guid that can be found in the rss/atom feed. Might not be set. @@ -261,6 +262,17 @@ public class FeedItem extends FeedComponent implements }; } + @Override + public Uri getImageUri() { + if (hasMedia()) { + return media.getImageUri(); + } else if (feed != null) { + return feed.getImageUri(); + } else { + return null; + } + } + public enum State { NEW, IN_PROGRESS, READ, PLAYING } @@ -277,45 +289,6 @@ public class FeedItem extends FeedComponent implements return (isRead() ? State.READ : State.NEW); } - @Override - public InputStream openImageInputStream() { - InputStream out = null; - if (hasItemImageDownloaded()) { - out = image.openImageInputStream(); - } else if (hasMedia()) { - out = media.openImageInputStream(); - } else if (feed.getImage() != null) { - out = feed.getImage().openImageInputStream(); - } - return out; - } - - @Override - public InputStream reopenImageInputStream(InputStream input) { - InputStream out = null; - if (hasItemImageDownloaded()) { - out = image.reopenImageInputStream(input); - } else if (hasMedia()) { - out = media.reopenImageInputStream(input); - } else if (feed.getImage() != null) { - out = feed.getImage().reopenImageInputStream(input); - } - return out; - } - - @Override - public String getImageLoaderCacheKey() { - String out = null; - if (hasItemImageDownloaded()) { - out = image.getImageLoaderCacheKey(); - } else if (hasMedia()) { - out = media.getImageLoaderCacheKey(); - } else if (feed.getImage() != null) { - out = feed.getImage().getImageLoaderCacheKey(); - } - return out; - } - public long getFeedId() { return feedId; } diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java index dc941cb48..f555654d0 100644 --- a/src/de/danoeh/antennapod/feed/FeedMedia.java +++ b/src/de/danoeh/antennapod/feed/FeedMedia.java @@ -2,21 +2,24 @@ package de.danoeh.antennapod.feed; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -import de.danoeh.antennapod.PodcastApp; -import de.danoeh.antennapod.preferences.PlaybackPreferences; -import de.danoeh.antennapod.storage.DBReader; -import de.danoeh.antennapod.storage.DBWriter; -import de.danoeh.antennapod.util.ChapterUtils; -import de.danoeh.antennapod.util.playback.Playable; +import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.Date; import java.util.List; import java.util.concurrent.Callable; +import de.danoeh.antennapod.PodcastApp; +import de.danoeh.antennapod.preferences.PlaybackPreferences; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.storage.DBWriter; +import de.danoeh.antennapod.util.ChapterUtils; +import de.danoeh.antennapod.util.playback.Playable; + public class FeedMedia extends FeedFile implements Playable { private static final String TAG = "FeedMedia"; @@ -382,52 +385,13 @@ public class FeedMedia extends FeedFile implements Playable { }; @Override - public InputStream openImageInputStream() { - InputStream out; - if (item.hasItemImageDownloaded()) { - out = item.openImageInputStream(); + public Uri getImageUri() { + if (localFileAvailable()) { + return new Uri.Builder().scheme(SCHEME_MEDIA).encodedPath(getLocalMediaUrl()).build(); + } else if (item != null && item.getFeed() != null) { + return item.getFeed().getImageUri(); } else { - out = new Playable.DefaultPlayableImageLoader(this) - .openImageInputStream(); - } - if (out == null) { - if (item.getFeed().getImage() != null) { - return item.getFeed().getImage().openImageInputStream(); - } - } - return out; - } - - @Override - public String getImageLoaderCacheKey() { - String out; - if (item == null) { return null; - } else if (item.hasItemImageDownloaded()) { - out = item.getImageLoaderCacheKey(); - } else { - out = new Playable.DefaultPlayableImageLoader(this) - .getImageLoaderCacheKey(); - } - if (out == null) { - if (item.getFeed().getImage() != null) { - return item.getFeed().getImage().getImageLoaderCacheKey(); - } - } - return out; - } - - @Override - public InputStream reopenImageInputStream(InputStream input) { - if (input instanceof FileInputStream) { - if (item.hasItemImageDownloaded()) { - return item.getImage().reopenImageInputStream(input); - } else { - return item.getFeed().getImage().reopenImageInputStream(input); - } - } else { - return new Playable.DefaultPlayableImageLoader(this) - .reopenImageInputStream(input); } } } diff --git a/src/de/danoeh/antennapod/fragment/CoverFragment.java b/src/de/danoeh/antennapod/fragment/CoverFragment.java index 0e1fe35e0..ffce518bf 100644 --- a/src/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/src/de/danoeh/antennapod/fragment/CoverFragment.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.fragment; +import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; @@ -7,91 +8,98 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; + import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.util.playback.Playable; -/** Displays the cover and the title of a FeedItem. */ +/** + * Displays the cover and the title of a FeedItem. + */ public class CoverFragment extends Fragment implements - AudioplayerContentFragment { - private static final String TAG = "CoverFragment"; - private static final String ARG_PLAYABLE = "arg.playable"; + AudioplayerContentFragment { + private static final String TAG = "CoverFragment"; + private static final String ARG_PLAYABLE = "arg.playable"; - private Playable media; + private Playable media; - private ImageView imgvCover; + private ImageView imgvCover; - private boolean viewCreated = false; + private boolean viewCreated = false; - public static CoverFragment newInstance(Playable item) { - CoverFragment f = new CoverFragment(); - if (item != null) { - Bundle args = new Bundle(); - args.putParcelable(ARG_PLAYABLE, item); - f.setArguments(args); - } - return f; - } + public static CoverFragment newInstance(Playable item) { + CoverFragment f = new CoverFragment(); + if (item != null) { + Bundle args = new Bundle(); + args.putParcelable(ARG_PLAYABLE, item); + f.setArguments(args); + } + return f; + } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setRetainInstance(true); - Bundle args = getArguments(); - if (args != null) { - media = args.getParcelable(ARG_PLAYABLE); - } else { - Log.e(TAG, TAG + " was called with invalid arguments"); - } - } + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + Bundle args = getArguments(); + if (args != null) { + media = args.getParcelable(ARG_PLAYABLE); + } else { + Log.e(TAG, TAG + " was called with invalid arguments"); + } + } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.cover_fragment, container, false); - imgvCover = (ImageView) root.findViewById(R.id.imgvCover); - viewCreated = true; - return root; - } + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.cover_fragment, container, false); + imgvCover = (ImageView) root.findViewById(R.id.imgvCover); + viewCreated = true; + return root; + } - private void loadMediaInfo() { - if (media != null) { - imgvCover.post(new Runnable() { + private void loadMediaInfo() { + if (media != null) { + imgvCover.post(new Runnable() { - @Override - public void run() { - ImageLoader.getInstance().loadCoverBitmap( - media, imgvCover); - } - }); - } else { - Log.w(TAG, "loadMediaInfo was called while media was null"); - } - } + @Override + public void run() { + Context c = getActivity(); + if (c != null) { + PicassoProvider.getMediaMetadataPicassoInstance(c) + .load(media.getImageUri()) + .into(imgvCover); + } + } + }); + } else { + Log.w(TAG, "loadMediaInfo was called while media was null"); + } + } - @Override - public void onStart() { - if (BuildConfig.DEBUG) - Log.d(TAG, "On Start"); - super.onStart(); - if (media != null) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Loading media info"); - loadMediaInfo(); - } else { - Log.w(TAG, "Unable to load media info: media was null"); - } - } + @Override + public void onStart() { + if (BuildConfig.DEBUG) + Log.d(TAG, "On Start"); + super.onStart(); + if (media != null) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Loading media info"); + loadMediaInfo(); + } else { + Log.w(TAG, "Unable to load media info: media was null"); + } + } - @Override - public void onDataSetChanged(Playable media) { - this.media = media; - if (viewCreated) { - loadMediaInfo(); - } + @Override + public void onDataSetChanged(Playable media) { + this.media = media; + if (viewCreated) { + loadMediaInfo(); + } - } + } } diff --git a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java index db47cd8a4..77587194b 100644 --- a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -10,9 +10,10 @@ import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; + import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.service.playback.PlaybackService; import de.danoeh.antennapod.util.Converter; import de.danoeh.antennapod.util.playback.Playable; @@ -23,215 +24,216 @@ import de.danoeh.antennapod.util.playback.PlaybackController; * if the PlaybackService is running */ public class ExternalPlayerFragment extends Fragment { - private static final String TAG = "ExternalPlayerFragment"; - - private ViewGroup fragmentLayout; - private ImageView imgvCover; - private ViewGroup layoutInfo; - private TextView txtvTitle; - private ImageButton butPlay; - - private PlaybackController controller; - - public ExternalPlayerFragment() { - super(); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View root = inflater.inflate(R.layout.external_player_fragment, - container, false); - fragmentLayout = (ViewGroup) root.findViewById(R.id.fragmentLayout); - imgvCover = (ImageView) root.findViewById(R.id.imgvCover); - layoutInfo = (ViewGroup) root.findViewById(R.id.layoutInfo); - txtvTitle = (TextView) root.findViewById(R.id.txtvTitle); - butPlay = (ImageButton) root.findViewById(R.id.butPlay); - - layoutInfo.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (BuildConfig.DEBUG) - Log.d(TAG, "layoutInfo was clicked"); - - if (controller.getMedia() != null) { - startActivity(PlaybackService.getPlayerActivityIntent( - getActivity(), controller.getMedia())); - } - } - }); - return root; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - controller = setupPlaybackController(); - butPlay.setOnClickListener(controller.newOnPlayButtonClickListener()); - } - - private PlaybackController setupPlaybackController() { - return new PlaybackController(getActivity(), true) { - - @Override - public void setupGUI() { - } - - @Override - public void onPositionObserverUpdate() { - } - - @Override - public void onReloadNotification(int code) { - } - - @Override - public void onBufferStart() { - // TODO Auto-generated method stub - - } - - @Override - public void onBufferEnd() { - // TODO Auto-generated method stub - - } - - @Override - public void onBufferUpdate(float progress) { - } - - @Override - public void onSleepTimerUpdate() { - } - - @Override - public void handleError(int code) { - } - - @Override - public ImageButton getPlayButton() { - return butPlay; - } - - @Override - public void postStatusMsg(int msg) { - } - - @Override - public void clearStatusMsg() { - } - - @Override - public boolean loadMediaInfo() { + private static final String TAG = "ExternalPlayerFragment"; + + private ViewGroup fragmentLayout; + private ImageView imgvCover; + private ViewGroup layoutInfo; + private TextView txtvTitle; + private ImageButton butPlay; + + private PlaybackController controller; + + public ExternalPlayerFragment() { + super(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.external_player_fragment, + container, false); + fragmentLayout = (ViewGroup) root.findViewById(R.id.fragmentLayout); + imgvCover = (ImageView) root.findViewById(R.id.imgvCover); + layoutInfo = (ViewGroup) root.findViewById(R.id.layoutInfo); + txtvTitle = (TextView) root.findViewById(R.id.txtvTitle); + butPlay = (ImageButton) root.findViewById(R.id.butPlay); + + layoutInfo.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (BuildConfig.DEBUG) + Log.d(TAG, "layoutInfo was clicked"); + + if (controller.getMedia() != null) { + startActivity(PlaybackService.getPlayerActivityIntent( + getActivity(), controller.getMedia())); + } + } + }); + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + controller = setupPlaybackController(); + butPlay.setOnClickListener(controller.newOnPlayButtonClickListener()); + } + + private PlaybackController setupPlaybackController() { + return new PlaybackController(getActivity(), true) { + + @Override + public void setupGUI() { + } + + @Override + public void onPositionObserverUpdate() { + } + + @Override + public void onReloadNotification(int code) { + } + + @Override + public void onBufferStart() { + // TODO Auto-generated method stub + + } + + @Override + public void onBufferEnd() { + // TODO Auto-generated method stub + + } + + @Override + public void onBufferUpdate(float progress) { + } + + @Override + public void onSleepTimerUpdate() { + } + + @Override + public void handleError(int code) { + } + + @Override + public ImageButton getPlayButton() { + return butPlay; + } + + @Override + public void postStatusMsg(int msg) { + } + + @Override + public void clearStatusMsg() { + } + + @Override + public boolean loadMediaInfo() { ExternalPlayerFragment fragment = ExternalPlayerFragment.this; if (fragment != null) { - return fragment.loadMediaInfo(); + return fragment.loadMediaInfo(); } else { return false; } - } - - @Override - public void onAwaitingVideoSurface() { - } - - @Override - public void onServiceQueried() { - } - - @Override - public void onShutdownNotification() { - if (fragmentLayout != null) { - fragmentLayout.setVisibility(View.GONE); - } - controller = setupPlaybackController(); - if (butPlay != null) { - butPlay.setOnClickListener(controller - .newOnPlayButtonClickListener()); - } - - } - - @Override - public void onPlaybackEnd() { - if (fragmentLayout != null) { - fragmentLayout.setVisibility(View.GONE); - } - controller = setupPlaybackController(); - if (butPlay != null) { - butPlay.setOnClickListener(controller - .newOnPlayButtonClickListener()); - } - } - - @Override - public void onPlaybackSpeedChange() { - // TODO Auto-generated method stub - - } - }; - } - - @Override - public void onResume() { - super.onResume(); - controller.init(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (BuildConfig.DEBUG) - Log.d(TAG, "Fragment is about to be destroyed"); - if (controller != null) { - controller.release(); - } - } - - @Override - public void onPause() { - super.onPause(); - if (controller != null) { - controller.pause(); - } - } - - private boolean loadMediaInfo() { - if (BuildConfig.DEBUG) - Log.d(TAG, "Loading media info"); - if (controller.serviceAvailable()) { - Playable media = controller.getMedia(); - if (media != null) { - txtvTitle.setText(media.getEpisodeTitle()); - ImageLoader.getInstance().loadThumbnailBitmap( - media, - imgvCover, - (int) getActivity().getResources().getDimension( - R.dimen.external_player_height)); - - fragmentLayout.setVisibility(View.VISIBLE); - if (controller.isPlayingVideo()) { - butPlay.setVisibility(View.GONE); - } else { - butPlay.setVisibility(View.VISIBLE); - } + } + + @Override + public void onAwaitingVideoSurface() { + } + + @Override + public void onServiceQueried() { + } + + @Override + public void onShutdownNotification() { + if (fragmentLayout != null) { + fragmentLayout.setVisibility(View.GONE); + } + controller = setupPlaybackController(); + if (butPlay != null) { + butPlay.setOnClickListener(controller + .newOnPlayButtonClickListener()); + } + + } + + @Override + public void onPlaybackEnd() { + if (fragmentLayout != null) { + fragmentLayout.setVisibility(View.GONE); + } + controller = setupPlaybackController(); + if (butPlay != null) { + butPlay.setOnClickListener(controller + .newOnPlayButtonClickListener()); + } + } + + @Override + public void onPlaybackSpeedChange() { + // TODO Auto-generated method stub + + } + }; + } + + @Override + public void onResume() { + super.onResume(); + controller.init(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (BuildConfig.DEBUG) + Log.d(TAG, "Fragment is about to be destroyed"); + if (controller != null) { + controller.release(); + } + } + + @Override + public void onPause() { + super.onPause(); + if (controller != null) { + controller.pause(); + } + } + + private boolean loadMediaInfo() { + if (BuildConfig.DEBUG) + Log.d(TAG, "Loading media info"); + if (controller.serviceAvailable()) { + Playable media = controller.getMedia(); + if (media != null) { + txtvTitle.setText(media.getEpisodeTitle()); + + int imageSize = (int) getResources().getDimension(R.dimen.external_player_height); + PicassoProvider.getMediaMetadataPicassoInstance(getActivity()) + .load(media.getImageUri()) + .resize(imageSize, imageSize) + .into(imgvCover); + + fragmentLayout.setVisibility(View.VISIBLE); + if (controller.isPlayingVideo()) { + butPlay.setVisibility(View.GONE); + } else { + butPlay.setVisibility(View.VISIBLE); + } return true; - } else { - Log.w(TAG, - "loadMediaInfo was called while the media object of playbackService was null!"); + } else { + Log.w(TAG, + "loadMediaInfo was called while the media object of playbackService was null!"); return false; - } - } else { - Log.w(TAG, - "loadMediaInfo was called while playbackService was null!"); + } + } else { + Log.w(TAG, + "loadMediaInfo was called while playbackService was null!"); return false; - } - } + } + } - private String getPositionString(int position, int duration) { - return Converter.getDurationStringLong(position) + " / " - + Converter.getDurationStringLong(duration); - } + private String getPositionString(int position, int duration) { + return Converter.getDurationStringLong(position) + " / " + + Converter.getDurationStringLong(duration); + } } diff --git a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java index d37f17b6d..5ef914f6c 100644 --- a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -34,7 +34,7 @@ import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; import de.danoeh.antennapod.adapter.FeedItemlistAdapter; import de.danoeh.antennapod.asynctask.DownloadObserver; import de.danoeh.antennapod.asynctask.FeedRemover; -import de.danoeh.antennapod.asynctask.ImageLoader; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.dialog.ConfirmationDialog; import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.dialog.FeedItemDialog; @@ -349,8 +349,13 @@ public class ItemlistFragment extends ListFragment { txtvTitle.setText(feed.getTitle()); txtvAuthor.setText(feed.getAuthor()); - ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(), imgvCover, - (int) getResources().getDimension(R.dimen.thumbnail_length_onlinefeedview)); + + int imageSize = (int) getResources().getDimension(R.dimen.thumbnail_length_onlinefeedview); + PicassoProvider.getDefaultPicassoInstance(getActivity()) + .load(feed.getImageUri()) + .resize(imageSize, imageSize) + .into(imgvCover); + if (feed.getLink() == null) { butVisitWebsite.setVisibility(View.INVISIBLE); } else { diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java index 163a57ed2..59d7ddbb9 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java @@ -4,7 +4,12 @@ import android.annotation.SuppressLint; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; -import android.content.*; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.AudioManager; @@ -26,11 +31,14 @@ import android.widget.Toast; import org.apache.commons.lang3.StringUtils; +import java.io.IOException; +import java.util.List; + import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.AudioplayerActivity; import de.danoeh.antennapod.activity.VideoplayerActivity; +import de.danoeh.antennapod.asynctask.PicassoProvider; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedMedia; @@ -41,14 +49,10 @@ import de.danoeh.antennapod.receiver.MediaButtonReceiver; import de.danoeh.antennapod.receiver.PlayerWidget; import de.danoeh.antennapod.storage.DBTasks; import de.danoeh.antennapod.storage.DBWriter; -import de.danoeh.antennapod.util.BitmapDecoder; import de.danoeh.antennapod.util.QueueAccess; -import de.danoeh.antennapod.util.flattr.FlattrThing; import de.danoeh.antennapod.util.flattr.FlattrUtils; import de.danoeh.antennapod.util.playback.Playable; -import java.util.List; - /** * Controls the MediaPlayer that plays a FeedMedia-file */ @@ -257,7 +261,8 @@ public class PlaybackService extends Service { } if ((flags & Service.START_FLAG_REDELIVERY) != 0) { - if (BuildConfig.DEBUG) Log.d(TAG, "onStartCommand is a redelivered intent, calling stopForeground now."); + if (BuildConfig.DEBUG) + Log.d(TAG, "onStartCommand is a redelivered intent, calling stopForeground now."); stopForeground(true); } else { @@ -678,11 +683,16 @@ public class PlaybackService extends Service { Log.d(TAG, "Starting background work"); if (android.os.Build.VERSION.SDK_INT >= 11) { if (info.playable != null) { - int iconSize = getResources().getDimensionPixelSize( - android.R.dimen.notification_large_icon_width); - icon = BitmapDecoder - .decodeBitmapFromWorkerTaskResource(iconSize, - info.playable); + try { + int iconSize = getResources().getDimensionPixelSize( + android.R.dimen.notification_large_icon_width); + icon = PicassoProvider.getMediaMetadataPicassoInstance(PlaybackService.this) + .load(info.playable.getImageUri()) + .resize(iconSize, iconSize) + .get(); + } catch (IOException e) { + e.printStackTrace(); + } } } @@ -766,7 +776,7 @@ public class PlaybackService extends Service { if (updatePlayedDuration && playable instanceof FeedMedia) { FeedMedia m = (FeedMedia) playable; FeedItem item = m.getItem(); - m.setPlayedDuration(m.getPlayedDuration() + ((int)(deltaPlayedDuration * playbackSpeed))); + m.setPlayedDuration(m.getPlayedDuration() + ((int) (deltaPlayedDuration * playbackSpeed))); // Auto flattr if (isAutoFlattrable(m) && (m.getPlayedDuration() > UserPreferences.getAutoFlattrPlayedDurationThreshold() * duration)) { @@ -778,8 +788,9 @@ public class PlaybackService extends Service { } } playable.saveCurrentPosition(PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()), - position); + .getDefaultSharedPreferences(getApplicationContext()), + position + ); } } diff --git a/src/de/danoeh/antennapod/util/BitmapDecoder.java b/src/de/danoeh/antennapod/util/BitmapDecoder.java deleted file mode 100644 index 5296d675a..000000000 --- a/src/de/danoeh/antennapod/util/BitmapDecoder.java +++ /dev/null @@ -1,50 +0,0 @@ -package de.danoeh.antennapod.util; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Rect; -import android.util.Log; -import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.asynctask.ImageLoader; -import org.apache.commons.io.IOUtils; - -import java.io.InputStream; - -public class BitmapDecoder { - private static final String TAG = "BitmapDecoder"; - - private static int calculateSampleSize(int preferredLength, int length) { - int sampleSize = 1; - if (length > preferredLength) { - sampleSize = Math.round(((float) length / (float) preferredLength)); - } - return sampleSize; - } - - public static Bitmap decodeBitmapFromWorkerTaskResource(int preferredLength, - ImageLoader.ImageWorkerTaskResource source) { - InputStream input = source.openImageInputStream(); - if (input != null) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeStream(input, new Rect(), options); - int srcWidth = options.outWidth; - int srcHeight = options.outHeight; - int length = Math.max(srcWidth, srcHeight); - int sampleSize = calculateSampleSize(preferredLength, length); - if (BuildConfig.DEBUG) - Log.d(TAG, "Using samplesize " + sampleSize); - options.inJustDecodeBounds = false; - options.inSampleSize = sampleSize; - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - Bitmap decodedBitmap = BitmapFactory.decodeStream(source.reopenImageInputStream(input), - null, options); - if (decodedBitmap == null) { - decodedBitmap = BitmapFactory.decodeStream(source.reopenImageInputStream(input)); - } - IOUtils.closeQuietly(input); - return decodedBitmap; - } - return null; - } -} diff --git a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java index 390498cea..3f6e6ae0a 100644 --- a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java +++ b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java @@ -3,12 +3,14 @@ package de.danoeh.antennapod.util.playback; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.media.MediaMetadataRetriever; +import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.MediaType; import de.danoeh.antennapod.util.ChapterUtils; +import java.io.File; import java.io.InputStream; import java.util.List; import java.util.concurrent.Callable; @@ -224,22 +226,12 @@ public class ExternalMedia implements Playable { } }; - @Override - public InputStream openImageInputStream() { - return new Playable.DefaultPlayableImageLoader(this) - .openImageInputStream(); - } - - @Override - public String getImageLoaderCacheKey() { - return new Playable.DefaultPlayableImageLoader(this) - .getImageLoaderCacheKey(); - } - - @Override - public InputStream reopenImageInputStream(InputStream input) { - return new Playable.DefaultPlayableImageLoader(this) - .reopenImageInputStream(input); - } - + @Override + public Uri getImageUri() { + if (localFileAvailable()) { + return new Uri.Builder().scheme(SCHEME_MEDIA).encodedPath(getLocalMediaUrl()).build(); + } else { + return null; + } + } } diff --git a/src/de/danoeh/antennapod/util/playback/Playable.java b/src/de/danoeh/antennapod/util/playback/Playable.java index 9ed45abfc..004ae56bb 100644 --- a/src/de/danoeh/antennapod/util/playback/Playable.java +++ b/src/de/danoeh/antennapod/util/playback/Playable.java @@ -2,27 +2,23 @@ package de.danoeh.antennapod.util.playback; import android.content.Context; import android.content.SharedPreferences; -import android.media.MediaMetadataRetriever; import android.os.Parcelable; import android.util.Log; -import de.danoeh.antennapod.asynctask.ImageLoader; + +import java.util.List; + +import de.danoeh.antennapod.asynctask.PicassoImageResource; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.feed.MediaType; import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.util.ShownotesProvider; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.Validate; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.List; /** * Interface for objects that can be played by the PlaybackService. */ public interface Playable extends Parcelable, - ImageLoader.ImageWorkerTaskResource, ShownotesProvider { + ShownotesProvider, PicassoImageResource { /** * Save information about the playable in a preference so that it can be @@ -208,69 +204,4 @@ public interface Playable extends Parcelable, } } - - /** - * Uses local file as image resource if it is available. - */ - public static class DefaultPlayableImageLoader implements - ImageLoader.ImageWorkerTaskResource { - private Playable playable; - - public DefaultPlayableImageLoader(Playable playable) { - Validate.notNull(playable); - - this.playable = playable; - } - - @Override - public InputStream openImageInputStream() { - if (playable.localFileAvailable() - && playable.getLocalMediaUrl() != null) { - MediaMetadataRetriever mmr = new MediaMetadataRetriever(); - try { - mmr.setDataSource(playable.getLocalMediaUrl()); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - return null; - } - byte[] imgData = mmr.getEmbeddedPicture(); - if (imgData != null) { - return new PublicByteArrayInputStream(imgData); - - } - } - return null; - } - - @Override - public String getImageLoaderCacheKey() { - return playable.getLocalMediaUrl(); - } - - @Override - public InputStream reopenImageInputStream(InputStream input) { - if (input instanceof PublicByteArrayInputStream) { - IOUtils.closeQuietly(input); - byte[] imgData = ((PublicByteArrayInputStream) input) - .getByteArray(); - if (imgData != null) { - ByteArrayInputStream out = new ByteArrayInputStream(imgData); - return out; - } - - } - return null; - } - - private static class PublicByteArrayInputStream extends - ByteArrayInputStream { - public PublicByteArrayInputStream(byte[] buf) { - super(buf); - } - - public byte[] getByteArray() { - return buf; - } - } - } } |