Replaced ImageLoader and DiskCache with Picasso
Implemented Picasso Downloaders Replaced ImageLoader and DiskCache with Picasso Removed ImageLoader, DiskCache code
This commit is contained in:
parent
460e061d35
commit
09c4736867
|
@ -34,6 +34,10 @@ dependencies {
|
|||
exclude group: 'com.android.support', module: 'support-v4'
|
||||
}
|
||||
compile 'org.jsoup:jsoup:1.7.3'
|
||||
compile 'com.squareup.picasso:picasso:2.3.+'
|
||||
compile 'com.squareup.okhttp:okhttp:2.0.+'
|
||||
compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
|
||||
compile 'com.squareup.okio:okio:1.0.0'
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
@ -50,6 +50,10 @@
|
|||
-keep public class org.jsoup.** {
|
||||
public *;
|
||||
}
|
||||
|
||||
-dontwarn com.squareup.okhttp.**
|
||||
-dontwarn okio.**
|
||||
|
||||
-keep class android.support.v4.** { *; }
|
||||
-keep interface android.support.v4.** { *; }
|
||||
-keep class android.support.v7.** { *; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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]));
|
||||
|
||||
|
|
|
@ -9,18 +9,14 @@ import android.util.Log;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.*;
|
||||
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.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
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 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;
|
||||
|
@ -31,6 +27,18 @@ 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.PicassoProvider;
|
||||
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
|
||||
/**
|
||||
* Default implementation of OnlineFeedViewActivity. Shows the downloaded feed's items with their descriptions,
|
||||
* a subscribe button and a spinner for choosing alternate feed URLs.
|
||||
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
public ExternalEpisodesListAdapter(Context context,
|
||||
ActionButtonCallback callback,
|
||||
OnGroupActionClicked groupActionCallback,
|
||||
ItemAccess itemAccess) {
|
||||
super();
|
||||
this.context = context;
|
||||
private final int imageSize;
|
||||
|
||||
public ExternalEpisodesListAdapter(Context context,
|
||||
ActionButtonCallback callback,
|
||||
OnGroupActionClicked groupActionCallback,
|
||||
ItemAccess itemAccess) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.itemAccess = itemAccess;
|
||||
this.feedItemActionCallback = callback;
|
||||
this.groupActionCallback = groupActionCallback;
|
||||
}
|
||||
this.feedItemActionCallback = callback;
|
||||
this.groupActionCallback = groupActionCallback;
|
||||
this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areAllItemsEnabled() {
|
||||
return true;
|
||||
}
|
||||
@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) {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
return childPosition;
|
||||
}
|
||||
@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);
|
||||
@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();
|
||||
}
|
||||
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();
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
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()));
|
||||
}
|
||||
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));
|
||||
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);
|
||||
}
|
||||
}
|
||||
} 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() {
|
||||
PicassoProvider.getMediaMetadataPicassoInstance(context)
|
||||
.load(item.getImageUri())
|
||||
.resize(imageSize, imageSize)
|
||||
.into(holder.feedImage);
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
feedItemActionCallback.onActionButtonPressed(item);
|
||||
}
|
||||
});
|
||||
holder.butAction.setFocusable(false);
|
||||
holder.butAction.setOnClickListener(new OnClickListener() {
|
||||
|
||||
return convertView;
|
||||
@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;
|
||||
}
|
||||
static class Holder {
|
||||
TextView title;
|
||||
TextView feedTitle;
|
||||
TextView lenSize;
|
||||
ImageView downloadStatus;
|
||||
ImageView feedImage;
|
||||
ImageButton butAction;
|
||||
View statusPlaying;
|
||||
ProgressBar episodeProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
// Hide 'unread items' group if empty
|
||||
if (itemAccess.getUnreadItemsSize() > 0) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@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 long getGroupId(int groupPosition) {
|
||||
return groupPosition;
|
||||
}
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
// Hide 'unread items' group if empty
|
||||
if (itemAccess.getUnreadItemsSize() > 0) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@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 long getGroupId(int groupPosition) {
|
||||
return groupPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
groupActionCallback.onClick(getGroupId(groupPosition));
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
@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);
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return itemAccess.getUnreadItemsSize() == 0
|
||||
&& itemAccess.getQueueSize() == 0;
|
||||
}
|
||||
String headerString = null;
|
||||
int childrenCount = 0;
|
||||
|
||||
@Override
|
||||
public Object getGroup(int groupPosition) {
|
||||
return null;
|
||||
}
|
||||
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 boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
groupActionCallback.onClick(getGroupId(groupPosition));
|
||||
}
|
||||
});
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return itemAccess.getUnreadItemsSize() == 0
|
||||
&& itemAccess.getQueueSize() == 0;
|
||||
}
|
||||
|
||||
public interface OnGroupActionClicked {
|
||||
public void onClick(long groupId);
|
||||
}
|
||||
@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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
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);
|
||||
// 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 = 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());
|
||||
}
|
||||
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(
|
||||
item.getFeed().getImage(),
|
||||
holder.cover,
|
||||
(int) convertView.getResources().getDimension(
|
||||
R.dimen.thumbnail_length));
|
||||
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());
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
PicassoProvider.getDefaultPicassoInstance(context)
|
||||
.load(item.getFeed().getImageUri())
|
||||
.resize(imageSize, imageSize)
|
||||
.into(holder.cover);
|
||||
|
||||
static class Holder {
|
||||
ImageView cover;
|
||||
TextView title;
|
||||
TextView subtitle;
|
||||
}
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
static class Holder {
|
||||
ImageView cover;
|
||||
TextView title;
|
||||
TextView subtitle;
|
||||
}
|
||||
|
||||
public static interface ItemAccess {
|
||||
int getCount();
|
||||
|
||||
SearchResult getItem(int position);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,17 @@ 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 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;
|
||||
|
@ -11,12 +20,6 @@ import de.danoeh.antennapod.storage.DBWriter;
|
|||
import de.danoeh.antennapod.util.ChapterUtils;
|
||||
import de.danoeh.antennapod.util.playback.Playable;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 static final String TAG = "ExternalPlayerFragment";
|
||||
|
||||
private ViewGroup fragmentLayout;
|
||||
private ImageView imgvCover;
|
||||
private ViewGroup layoutInfo;
|
||||
private TextView txtvTitle;
|
||||
private ImageButton butPlay;
|
||||
private ViewGroup fragmentLayout;
|
||||
private ImageView imgvCover;
|
||||
private ViewGroup layoutInfo;
|
||||
private TextView txtvTitle;
|
||||
private ImageButton butPlay;
|
||||
|
||||
private PlaybackController controller;
|
||||
private PlaybackController controller;
|
||||
|
||||
public ExternalPlayerFragment() {
|
||||
super();
|
||||
}
|
||||
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);
|
||||
@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() {
|
||||
layoutInfo.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(TAG, "layoutInfo was clicked");
|
||||
@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;
|
||||
}
|
||||
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());
|
||||
}
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
controller = setupPlaybackController();
|
||||
butPlay.setOnClickListener(controller.newOnPlayButtonClickListener());
|
||||
}
|
||||
|
||||
private PlaybackController setupPlaybackController() {
|
||||
return new PlaybackController(getActivity(), true) {
|
||||
private PlaybackController setupPlaybackController() {
|
||||
return new PlaybackController(getActivity(), true) {
|
||||
|
||||
@Override
|
||||
public void setupGUI() {
|
||||
}
|
||||
@Override
|
||||
public void setupGUI() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionObserverUpdate() {
|
||||
}
|
||||
@Override
|
||||
public void onPositionObserverUpdate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReloadNotification(int code) {
|
||||
}
|
||||
@Override
|
||||
public void onReloadNotification(int code) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBufferStart() {
|
||||
// TODO Auto-generated method stub
|
||||
@Override
|
||||
public void onBufferStart() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBufferEnd() {
|
||||
// TODO Auto-generated method stub
|
||||
@Override
|
||||
public void onBufferEnd() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBufferUpdate(float progress) {
|
||||
}
|
||||
@Override
|
||||
public void onBufferUpdate(float progress) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSleepTimerUpdate() {
|
||||
}
|
||||
@Override
|
||||
public void onSleepTimerUpdate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(int code) {
|
||||
}
|
||||
@Override
|
||||
public void handleError(int code) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageButton getPlayButton() {
|
||||
return butPlay;
|
||||
}
|
||||
@Override
|
||||
public ImageButton getPlayButton() {
|
||||
return butPlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postStatusMsg(int msg) {
|
||||
}
|
||||
@Override
|
||||
public void postStatusMsg(int msg) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearStatusMsg() {
|
||||
}
|
||||
@Override
|
||||
public void clearStatusMsg() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadMediaInfo() {
|
||||
@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 onAwaitingVideoSurface() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceQueried() {
|
||||
}
|
||||
@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 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 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 onPlaybackSpeedChange() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
controller.init();
|
||||
}
|
||||
@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 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();
|
||||
}
|
||||
}
|
||||
@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));
|
||||
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());
|
||||
|
||||
fragmentLayout.setVisibility(View.VISIBLE);
|
||||
if (controller.isPlayingVideo()) {
|
||||
butPlay.setVisibility(View.GONE);
|
||||
} else {
|
||||
butPlay.setVisibility(View.VISIBLE);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue