From 9dec0546bd76a6987a0b14e68a94965778a36a0e Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 7 Mar 2013 15:34:12 +0100 Subject: [PATCH 01/21] Mark item as 'read' when adding it to the queue, move item to top of queue when playing it --- .../danoeh/antennapod/feed/FeedManager.java | 52 +++++++++++++++++-- src/de/danoeh/antennapod/feed/FeedMedia.java | 4 -- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index e984da46a..9b66c904b 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -111,7 +111,8 @@ public class FeedManager { /** * Play FeedMedia and start the playback service + launch Mediaplayer - * Activity. + * Activity. The FeedItem belonging to the media is moved to the top of the + * queue. * * @param context * for starting the playbackservice @@ -149,6 +150,11 @@ public class FeedManager { context.startActivity(PlaybackService.getPlayerActivityIntent( context, media)); } + if (queue.contains(media.getItem())) { + moveQueueItem(context, queue.indexOf(media.getItem()), 0, true); + } else { + addQueueItemAt(context, media.getItem(), 0); + } } catch (MediaFileNotFoundException e) { e.printStackTrace(); if (PlaybackPreferences.getLastPlayedId() == media.getId()) { @@ -197,7 +203,8 @@ public class FeedManager { PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); SharedPreferences.Editor editor = prefs.edit(); editor.putLong(PlaybackPreferences.PREF_LAST_PLAYED_ID, -1); - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, -1); + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, + -1); editor.commit(); } @@ -605,7 +612,43 @@ public class FeedManager { } } - /** Adds FeedItems to the queue if they are not in the queue yet. */ + /** + * Adds a feeditem to the queue at the specified index if it is not in the + * queue yet. The item is marked as 'read'. + */ + public void addQueueItemAt(final Context context, final FeedItem item, + final int index) { + contentChanger.post(new Runnable() { + + @Override + public void run() { + if (!queue.contains(item)) { + queue.add(index, item); + if (!item.isRead()) { + markItemRead(context, item, true, false); + } + } + eventDist.sendQueueUpdateBroadcast(); + + dbExec.execute(new Runnable() { + + @Override + public void run() { + PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + adapter.setQueue(queue); + adapter.close(); + } + }); + } + }); + + } + + /** + * Adds FeedItems to the queue if they are not in the queue yet. The items + * are marked as 'read'. + */ public void addQueueItem(final Context context, final FeedItem... items) { if (items.length > 0) { contentChanger.post(new Runnable() { @@ -615,6 +658,9 @@ public class FeedManager { for (FeedItem item : items) { if (!queue.contains(item)) { queue.add(item); + if (!item.isRead()) { + markItemRead(context, item, true, false); + } } } eventDist.sendQueueUpdateBroadcast(); diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java index de87c63a1..dbf565535 100644 --- a/src/de/danoeh/antennapod/feed/FeedMedia.java +++ b/src/de/danoeh/antennapod/feed/FeedMedia.java @@ -257,10 +257,6 @@ public class FeedMedia extends FeedFile implements Playable { @Override public void onPlaybackStart() { - if (getItem().isRead() == false) { - FeedManager.getInstance().markItemRead(PodcastApp.getInstance(), - getItem(), true, false); - } } @Override From 58747d227a123f6a1ef3641e2941115bb52aace1 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 7 Mar 2013 16:01:14 +0100 Subject: [PATCH 02/21] Add item to queue once it's downloaded --- src/de/danoeh/antennapod/feed/FeedManager.java | 6 ------ .../antennapod/service/download/DownloadService.java | 9 ++++++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 9b66c904b..32e7f88f1 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -570,7 +570,6 @@ public class FeedManager { /** Downloads FeedItems if they have not been downloaded yet. */ public void downloadFeedItem(final Context context, FeedItem... items) throws DownloadRequestException { - List addToQueue = new ArrayList(); for (FeedItem item : items) { if (item.getMedia() != null @@ -591,13 +590,8 @@ public class FeedManager { } else { requester.downloadMedia(context, item.getMedia()); } - addToQueue.add(item); } } - if (UserPreferences.isAutoQueue()) { - addQueueItem(context, - addToQueue.toArray(new FeedItem[addToQueue.size()])); - } } /** diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java index 986491fb5..0aa06985d 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadService.java +++ b/src/de/danoeh/antennapod/service/download/DownloadService.java @@ -58,6 +58,7 @@ import de.danoeh.antennapod.feed.FeedImage; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedManager; import de.danoeh.antennapod.feed.FeedMedia; +import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.syndication.handler.FeedHandler; @@ -831,7 +832,7 @@ public class DownloadService extends Service { } finally { mediaplayer.release(); } - + if (media.getItem().getChapters() == null) { ChapterUtils.loadChaptersFromFileUrl(media); if (media.getItem().getChapters() != null) { @@ -847,6 +848,12 @@ public class DownloadService extends Service { manager.setFeedMedia(DownloadService.this, media); } + if (UserPreferences.isAutoQueue() + && !FeedManager.getInstance().isInQueue(media.getItem())) { + FeedManager.getInstance().addQueueItem(DownloadService.this, + media.getItem()); + } + downloadsBeingHandled -= 1; handler.post(new Runnable() { From ba0f294850ea0b1a4ec6417c7185019db97f7bcd Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 7 Mar 2013 16:07:10 +0100 Subject: [PATCH 03/21] Removed 'status unread' indicator from queue --- res/layout/external_itemlist_item.xml | 16 ---------------- .../adapter/ExternalEpisodesListAdapter.java | 8 -------- 2 files changed, 24 deletions(-) diff --git a/res/layout/external_itemlist_item.xml b/res/layout/external_itemlist_item.xml index fe1c29a19..c8a039925 100644 --- a/res/layout/external_itemlist_item.xml +++ b/res/layout/external_itemlist_item.xml @@ -81,22 +81,6 @@ android:layout_marginTop="4dp" android:layout_toLeftOf="@id/butAction" /> - - Date: Thu, 7 Mar 2013 18:52:47 +0100 Subject: [PATCH 04/21] Use progressbar for showing the listening progress of an episode --- res/layout/external_itemlist_item.xml | 29 ++++------- res/layout/feeditemlist_item.xml | 30 +++++------ .../adapter/ExternalEpisodesListAdapter.java | 49 ++++++++++------- .../adapter/InternalFeedItemlistAdapter.java | 52 ++++++++++++------- 4 files changed, 88 insertions(+), 72 deletions(-) diff --git a/res/layout/external_itemlist_item.xml b/res/layout/external_itemlist_item.xml index c8a039925..6f2405abc 100644 --- a/res/layout/external_itemlist_item.xml +++ b/res/layout/external_itemlist_item.xml @@ -32,8 +32,8 @@ android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginLeft="8dp" - android:layout_marginTop="8dp" android:layout_marginRight="4dp" + android:layout_marginTop="8dp" android:layout_toLeftOf="@id/butAction" android:layout_toRightOf="@id/imgvFeedimage" android:ellipsize="end" @@ -81,6 +81,16 @@ android:layout_marginTop="4dp" android:layout_toLeftOf="@id/butAction" /> + + - - \ No newline at end of file diff --git a/res/layout/feeditemlist_item.xml b/res/layout/feeditemlist_item.xml index 2cc7ee703..4fbddbbac 100644 --- a/res/layout/feeditemlist_item.xml +++ b/res/layout/feeditemlist_item.xml @@ -87,6 +87,19 @@ android:textColor="?android:attr/textColorTertiary" android:textSize="@dimen/text_size_micro" /> + + - - \ No newline at end of file diff --git a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java index 64eec8a38..30fcc2fd8 100644 --- a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java @@ -9,6 +9,7 @@ import android.view.ViewGroup; 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; @@ -89,8 +90,8 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { .findViewById(R.id.butAction); holder.statusPlaying = (View) convertView .findViewById(R.id.statusPlaying); - holder.statusInProgress = (TextView) convertView - .findViewById(R.id.statusInProgress); + holder.episodeProgress = (ProgressBar) convertView + .findViewById(R.id.pbar_episode_progress); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); @@ -98,36 +99,53 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { holder.title.setText(item.getTitle()); holder.feedTitle.setText(item.getFeed().getTitle()); + FeedItem.State state = item.getState(); if (groupPosition == GROUP_POS_QUEUE) { - FeedItem.State state = item.getState(); switch (state) { case PLAYING: holder.statusPlaying.setVisibility(View.VISIBLE); - holder.statusInProgress.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.VISIBLE); break; case IN_PROGRESS: holder.statusPlaying.setVisibility(View.GONE); - holder.statusInProgress.setVisibility(View.VISIBLE); - holder.statusInProgress.setText(Converter - .getDurationStringLong(item.getMedia().getPosition())); + holder.episodeProgress.setVisibility(View.VISIBLE); break; case NEW: holder.statusPlaying.setVisibility(View.GONE); - holder.statusInProgress.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); break; default: holder.statusPlaying.setVisibility(View.GONE); - holder.statusInProgress.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); break; } } else { holder.statusPlaying.setVisibility(View.GONE); - holder.statusInProgress.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); } FeedMedia media = item.getMedia(); if (media != null) { + + if (state == FeedItem.State.PLAYING + || state == FeedItem.State.IN_PROGRESS) { + if (media.getDuration() > 0) { + holder.episodeProgress.setProgress((int) (((double) media + .getPosition()) / media.getDuration() * 100)); + holder.lenSize.setText(Converter + .getDurationStringLong(media.getDuration() + - media.getPosition())); + } + } else if (!media.isDownloaded()) { + holder.lenSize.setText(context.getString(R.string.size_prefix) + + Converter.byteToString(media.getSize())); + } else { + holder.lenSize.setText(context + .getString(R.string.length_prefix) + + Converter.getDurationStringLong(media.getDuration())); + } + TypedArray drawables = context.obtainStyledAttributes(new int[] { R.attr.av_download, R.attr.navigation_refresh }); holder.lenSize.setVisibility(View.VISIBLE); @@ -137,20 +155,15 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { holder.downloadStatus.setImageDrawable(drawables .getDrawable(1)); } else { - holder.downloadStatus.setVisibility(View.GONE); + holder.downloadStatus.setVisibility(View.INVISIBLE); } - holder.lenSize.setText(context.getString(R.string.size_prefix) - + Converter.byteToString(media.getSize())); } else { holder.downloadStatus.setVisibility(View.VISIBLE); holder.downloadStatus .setImageDrawable(drawables.getDrawable(0)); - holder.lenSize.setText(context - .getString(R.string.length_prefix) - + Converter.getDurationStringLong(media.getDuration())); } } else { - holder.downloadStatus.setVisibility(View.GONE); + holder.downloadStatus.setVisibility(View.INVISIBLE); holder.lenSize.setVisibility(View.INVISIBLE); } @@ -182,7 +195,7 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { ImageView feedImage; ImageButton butAction; View statusPlaying; - TextView statusInProgress; + ProgressBar episodeProgress; } @Override diff --git a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java index c8d41b10e..7b898385e 100644 --- a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java @@ -12,10 +12,12 @@ import android.view.ViewGroup; import android.widget.Adapter; 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.feed.FeedItem; import de.danoeh.antennapod.feed.FeedManager; +import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.feed.MediaType; import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.Converter; @@ -72,8 +74,8 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter { .findViewById(R.id.statusPlaying); holder.statusUnread = (View) convertView .findViewById(R.id.statusUnread); - holder.statusInProgress = (TextView) convertView - .findViewById(R.id.statusInProgress); + holder.episodeProgress = (ProgressBar) convertView + .findViewById(R.id.pbar_episode_progress); convertView.setTag(holder); } else { @@ -99,24 +101,22 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter { case PLAYING: holder.statusPlaying.setVisibility(View.VISIBLE); holder.statusUnread.setVisibility(View.GONE); - holder.statusInProgress.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.VISIBLE); break; case IN_PROGRESS: holder.statusPlaying.setVisibility(View.GONE); holder.statusUnread.setVisibility(View.GONE); - holder.statusInProgress.setVisibility(View.VISIBLE); - holder.statusInProgress.setText(Converter - .getDurationStringLong(item.getMedia().getPosition())); + holder.episodeProgress.setVisibility(View.VISIBLE); break; case NEW: holder.statusPlaying.setVisibility(View.GONE); holder.statusUnread.setVisibility(View.VISIBLE); - holder.statusInProgress.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); break; default: holder.statusPlaying.setVisibility(View.GONE); holder.statusUnread.setVisibility(View.GONE); - holder.statusInProgress.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); break; } @@ -126,13 +126,36 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter { System.currentTimeMillis(), DateFormat.MEDIUM, DateFormat.SHORT)); - if (item.getMedia() == null) { + FeedMedia media = item.getMedia(); + if (media == null) { holder.downloaded.setVisibility(View.GONE); holder.downloading.setVisibility(View.GONE); holder.inPlaylist.setVisibility(View.GONE); holder.type.setVisibility(View.GONE); holder.lenSize.setVisibility(View.GONE); } else { + + 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(getContext().getString( + R.string.size_prefix) + + Converter.byteToString(media.getSize())); + } else { + holder.lenSize.setText(getContext().getString( + R.string.length_prefix) + + Converter.getDurationStringLong(media + .getDuration())); + } + holder.lenSize.setVisibility(View.VISIBLE); if (FeedManager.getInstance().isInQueue(item)) { holder.inPlaylist.setVisibility(View.VISIBLE); @@ -140,17 +163,8 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter { holder.inPlaylist.setVisibility(View.GONE); } if (item.getMedia().isDownloaded()) { - holder.lenSize.setText(convertView.getResources() - .getString(R.string.length_prefix) - + Converter.getDurationStringLong(item.getMedia() - .getDuration())); holder.downloaded.setVisibility(View.VISIBLE); } else { - holder.lenSize - .setText(convertView.getResources().getString( - R.string.size_prefix) - + Converter.byteToString(item.getMedia() - .getSize())); holder.downloaded.setVisibility(View.GONE); } @@ -200,7 +214,7 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter { ImageButton butAction; View statusUnread; View statusPlaying; - TextView statusInProgress; + ProgressBar episodeProgress; } public int getSelectedItemIndex() { From b45bd0124c3da5f48e615beb5b636fdc5f8447cd Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 7 Mar 2013 18:57:39 +0100 Subject: [PATCH 05/21] Fixed PlaybackService crash when seeking in INITIALIZING or PREPARING state --- src/de/danoeh/antennapod/service/PlaybackService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/de/danoeh/antennapod/service/PlaybackService.java b/src/de/danoeh/antennapod/service/PlaybackService.java index 450f7f65d..a30b40ce0 100644 --- a/src/de/danoeh/antennapod/service/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/PlaybackService.java @@ -1005,7 +1005,9 @@ public class PlaybackService extends Service { public void seek(int i) { saveCurrentPosition(); - if (status == PlayerStatus.INITIALIZED) { + if (status == PlayerStatus.INITIALIZED + || status == PlayerStatus.INITIALIZING + || status == PlayerStatus.PREPARING) { media.setPosition(i); setStartWhenPrepared(true); prepare(); From 7607647b11980d28801cd348e899ec2c415610fd Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 7 Mar 2013 19:03:35 +0100 Subject: [PATCH 06/21] Fixed typo --- src/de/danoeh/antennapod/preferences/PlaybackPreferences.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java index b93b2e07c..82a6df190 100644 --- a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java +++ b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java @@ -136,7 +136,7 @@ public class PlaybackPreferences implements } else if (key.equals(PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED)) { autoDeleteMediaPlaybackCompleted = sp.getBoolean( - PREF_AUTODELETE_MEDIA_ID, false); + PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, false); } else if (key.equals(PREF_AUTODELETE_MEDIA_ID)) { autoDeleteMediaId = sp.getLong(PREF_AUTODELETE_MEDIA_ID, -1); } else if (key.equals(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID)) { From ae17c74e3b35aaab7d6fb030eec416bddaa9d26c Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 7 Mar 2013 19:16:43 +0100 Subject: [PATCH 07/21] PlaybackService will now always load the next episode if it is available --- .../antennapod/service/PlaybackService.java | 155 ++++++++++-------- 1 file changed, 83 insertions(+), 72 deletions(-) diff --git a/src/de/danoeh/antennapod/service/PlaybackService.java b/src/de/danoeh/antennapod/service/PlaybackService.java index a30b40ce0..82f0cb644 100644 --- a/src/de/danoeh/antennapod/service/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/PlaybackService.java @@ -673,78 +673,7 @@ public class PlaybackService extends Service { @Override public void onCompletion(MediaPlayer mp) { - if (AppConfig.DEBUG) - Log.d(TAG, "Playback completed"); - audioManager.abandonAudioFocus(audioFocusChangeListener); - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - SharedPreferences.Editor editor = prefs.edit(); - - // Save state - cancelPositionSaver(); - - boolean isInQueue = false; - FeedItem nextItem = null; - - if (media instanceof FeedMedia) { - FeedItem item = ((FeedMedia) media).getItem(); - ((FeedMedia) media).setPlaybackCompletionDate(new Date()); - manager.markItemRead(PlaybackService.this, item, true, true); - nextItem = manager.getQueueSuccessorOfItem(item); - isInQueue = media instanceof FeedMedia - && manager.isInQueue(((FeedMedia) media).getItem()); - if (isInQueue) { - manager.removeQueueItem(PlaybackService.this, item); - } - manager.addItemToPlaybackHistory(PlaybackService.this, item); - manager.setFeedMedia(PlaybackService.this, (FeedMedia) media); - long autoDeleteMediaId = ((FeedComponent) media).getId(); - if (shouldStream) { - autoDeleteMediaId = -1; - } - editor.putLong(PlaybackPreferences.PREF_AUTODELETE_MEDIA_ID, - autoDeleteMediaId); - } - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.putBoolean( - PlaybackPreferences.PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, - true); - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.commit(); - - // Prepare for playing next item - boolean playNextItem = isInQueue && UserPreferences.isFollowQueue() - && nextItem != null; - if (playNextItem) { - if (AppConfig.DEBUG) - Log.d(TAG, "Loading next item in queue"); - media = nextItem.getMedia(); - shouldStream = !media.localFileAvailable(); - prepareImmediately = startWhenPrepared = true; - } else { - if (AppConfig.DEBUG) - Log.d(TAG, - "No more episodes available to play; Reloading current episode"); - prepareImmediately = startWhenPrepared = false; - stopForeground(true); - stopWidgetUpdater(); - } - int notificationCode = 0; - if (media.getMediaType() == MediaType.AUDIO) { - notificationCode = EXTRA_CODE_AUDIO; - playingVideo = false; - } else if (media.getMediaType() == MediaType.VIDEO) { - notificationCode = EXTRA_CODE_VIDEO; - } - resetVideoSurface(); - refreshRemoteControlClientState(); - sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, - notificationCode); + endPlayback(true); } }; @@ -757,6 +686,88 @@ public class PlaybackService extends Service { } }; + private void endPlayback(boolean playNextEpisode) { + if (AppConfig.DEBUG) + Log.d(TAG, "Playback completed"); + audioManager.abandonAudioFocus(audioFocusChangeListener); + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + SharedPreferences.Editor editor = prefs.edit(); + + // Save state + cancelPositionSaver(); + + boolean isInQueue = false; + FeedItem nextItem = null; + + if (media instanceof FeedMedia) { + FeedItem item = ((FeedMedia) media).getItem(); + ((FeedMedia) media).setPlaybackCompletionDate(new Date()); + manager.markItemRead(PlaybackService.this, item, true, true); + nextItem = manager.getQueueSuccessorOfItem(item); + isInQueue = media instanceof FeedMedia + && manager.isInQueue(((FeedMedia) media).getItem()); + if (isInQueue) { + manager.removeQueueItem(PlaybackService.this, item); + } + manager.addItemToPlaybackHistory(PlaybackService.this, item); + manager.setFeedMedia(PlaybackService.this, (FeedMedia) media); + long autoDeleteMediaId = ((FeedComponent) media).getId(); + if (shouldStream) { + autoDeleteMediaId = -1; + } + editor.putLong(PlaybackPreferences.PREF_AUTODELETE_MEDIA_ID, + autoDeleteMediaId); + } + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.putBoolean( + PlaybackPreferences.PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, + true); + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.commit(); + + // Load next episode if previous episode was in the queue and if there + // is an episode in the queue left. + // Start playback immediately if continuous playback is enabled + boolean loadNextItem = isInQueue && nextItem != null; + playNextEpisode = playNextEpisode && loadNextItem + && UserPreferences.isFollowQueue(); + if (loadNextItem) { + if (AppConfig.DEBUG) + Log.d(TAG, "Loading next item in queue"); + media = nextItem.getMedia(); + } + + if (playNextEpisode) { + if (AppConfig.DEBUG) + Log.d(TAG, "Playback of next episode will start immediately."); + prepareImmediately = startWhenPrepared = true; + } else { + if (AppConfig.DEBUG) + Log.d(TAG, + "No more episodes available to play; Reloading current episode"); + prepareImmediately = startWhenPrepared = false; + stopForeground(true); + stopWidgetUpdater(); + } + + int notificationCode = 0; + shouldStream = !media.localFileAvailable(); + if (media.getMediaType() == MediaType.AUDIO) { + notificationCode = EXTRA_CODE_AUDIO; + playingVideo = false; + } else if (media.getMediaType() == MediaType.VIDEO) { + notificationCode = EXTRA_CODE_VIDEO; + } + resetVideoSurface(); + refreshRemoteControlClientState(); + sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, notificationCode); + } + public void setSleepTimer(long waitingTime) { if (AppConfig.DEBUG) Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime) From 3e25aa4ea37604e765878a470f098ee810502520 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 7 Mar 2013 19:35:48 +0100 Subject: [PATCH 08/21] Made sure that first queue item can't be moved while it's playing --- .../activity/OrganizeQueueActivity.java | 27 ++++++++++++++++--- .../danoeh/antennapod/feed/FeedManager.java | 16 +++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java index 56e42f79f..50780844d 100644 --- a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java +++ b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java @@ -72,7 +72,10 @@ public class OrganizeQueueActivity extends SherlockListActivity { @Override public void drop(int from, int to) { FeedManager manager = FeedManager.getInstance(); - manager.moveQueueItem(OrganizeQueueActivity.this, from, to, false); + int offset = (manager.firstQueueItemIsPlaying()) ? 1 : 0; + + manager.moveQueueItem(OrganizeQueueActivity.this, from + offset, to + + offset, false); adapter.notifyDataSetChanged(); } }; @@ -82,6 +85,7 @@ public class OrganizeQueueActivity extends SherlockListActivity { @Override public void remove(int which) { FeedManager manager = FeedManager.getInstance(); + manager.removeQueueItem(OrganizeQueueActivity.this, (FeedItem) getListAdapter().getItem(which)); } @@ -110,9 +114,15 @@ public class OrganizeQueueActivity extends SherlockListActivity { } } + /** + * WARNING: If the PlaybackService is playing an episode from the queue, + * this list adapter will ignore the first item in the list to make sure + * that the position of the first queue item cannot be changed. + */ private static class OrganizeAdapter extends BaseAdapter { private Context context; + private FeedManager manager = FeedManager.getInstance(); public OrganizeAdapter(Context context) { super(); @@ -164,13 +174,22 @@ public class OrganizeQueueActivity extends SherlockListActivity { @Override public int getCount() { - return FeedManager.getInstance().getQueueSize(true); + int queueSize = manager.getQueueSize(true); + if (manager.firstQueueItemIsPlaying()) { + return queueSize - 1; + } else { + return queueSize; + } } @Override public FeedItem getItem(int position) { - return FeedManager.getInstance() - .getQueueItemAtIndex(position, true); + if (manager.firstQueueItemIsPlaying() && position < getCount()) { + return manager.getQueueItemAtIndex(position + 1, true); + } else { + return manager.getQueueItemAtIndex(position, true); + } + } @Override diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 32e7f88f1..3203a5e21 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -1560,6 +1560,22 @@ public class FeedManager { } } + /** + * Returns true if the first item in the queue is currently being played or + * false otherwise. If the queue is empty, this method will also return + * false. + * */ + public boolean firstQueueItemIsPlaying() { + FeedManager manager = FeedManager.getInstance(); + int queueSize = manager.getQueueSize(true); + if (queueSize == 0) { + return false; + } else { + FeedItem item = getQueueItemAtIndex(0, true); + return item.getState() == FeedItem.State.PLAYING; + } + } + /** * Returns the number of unread items. * From 5876b98bb80309d09e85ca4c0967f5e3d74bff5d Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 7 Mar 2013 20:02:23 +0100 Subject: [PATCH 09/21] Implemented skip functionality --- res/menu/feeditem.xml | 3 +- res/menu/mediaplayer.xml | 20 ++- res/values/ids.xml | 1 + res/values/strings.xml | 1 + .../activity/MediaplayerActivity.java | 6 +- .../antennapod/service/PlaybackService.java | 115 ++++++++++++------ .../util/menuhandler/FeedItemMenuHandler.java | 15 ++- 7 files changed, 115 insertions(+), 46 deletions(-) diff --git a/res/menu/feeditem.xml b/res/menu/feeditem.xml index a76f2c658..09b7fa6b0 100644 --- a/res/menu/feeditem.xml +++ b/res/menu/feeditem.xml @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/res/menu/mediaplayer.xml b/res/menu/mediaplayer.xml index 4f3a55114..2cde6d58a 100644 --- a/res/menu/mediaplayer.xml +++ b/res/menu/mediaplayer.xml @@ -1,7 +1,18 @@ - + + + + @@ -19,7 +30,10 @@ android:title="@string/support_label" android:visible="false"> - - + \ No newline at end of file diff --git a/res/values/ids.xml b/res/values/ids.xml index 476969668..4d393e675 100644 --- a/res/values/ids.xml +++ b/res/values/ids.xml @@ -14,5 +14,6 @@ + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 906d530d7..a1c9e336a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -70,6 +70,7 @@ Flattr this Enqueue all Download all + Skip episode Download successful diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java index c217a4628..10a879c06 100644 --- a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -227,7 +227,7 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity media != null && media.getWebsiteLink() != null); menu.findItem(R.id.visit_website_item).setVisible( media != null && media.getWebsiteLink() != null); - + menu.findItem(R.id.skip_episode_item).setVisible(media != null); boolean sleepTimerSet = controller.sleepTimerActive(); boolean sleepTimerNotSet = controller.sleepTimerNotActive(); menu.findItem(R.id.set_sleeptimer_item).setVisible(sleepTimerNotSet); @@ -303,6 +303,10 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity case R.id.share_link_item: ShareUtils.shareLink(this, media.getWebsiteLink()); break; + case R.id.skip_episode_item: + sendBroadcast(new Intent( + PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); + break; default: return false; diff --git a/src/de/danoeh/antennapod/service/PlaybackService.java b/src/de/danoeh/antennapod/service/PlaybackService.java index 82f0cb644..927413c4d 100644 --- a/src/de/danoeh/antennapod/service/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/PlaybackService.java @@ -85,6 +85,12 @@ public class PlaybackService extends Service { */ public static final String ACTION_SHUTDOWN_PLAYBACK_SERVICE = "action.de.danoeh.antennapod.service.actionShutdownPlaybackService"; + /** + * If the PlaybackService receives this action, it will end playback of the + * current episode and load the next episode if there is one available. + * */ + public static final String ACTION_SKIP_CURRENT_EPISODE = "action.de.danoeh.antennapod.service.skipCurrentEpisode"; + /** Used in NOTIFICATION_TYPE_RELOAD. */ public static final int EXTRA_CODE_AUDIO = 1; public static final int EXTRA_CODE_VIDEO = 2; @@ -266,6 +272,7 @@ public class PlaybackService extends Service { ACTION_SHUTDOWN_PLAYBACK_SERVICE)); registerReceiver(audioBecomingNoisy, new IntentFilter( AudioManager.ACTION_AUDIO_BECOMING_NOISY)); + registerReceiver(skipCurrentEpisodeReceiver, new IntentFilter(ACTION_SKIP_CURRENT_EPISODE)); } @@ -296,6 +303,7 @@ public class PlaybackService extends Service { unregisterReceiver(headsetDisconnected); unregisterReceiver(shutdownReceiver); unregisterReceiver(audioBecomingNoisy); + unregisterReceiver(skipCurrentEpisodeReceiver); if (android.os.Build.VERSION.SDK_INT >= 14) { audioManager.unregisterRemoteControlClient(remoteControlClient); } @@ -460,25 +468,28 @@ public class PlaybackService extends Service { @Override protected void onPostExecute(Playable result) { - if (result != null) { - try { - if (shouldStream) { - player.setDataSource(media.getStreamUrl()); - setStatus(PlayerStatus.PREPARING); - player.prepareAsync(); - } else { - player.setDataSource(media - .getLocalMediaUrl()); - setStatus(PlayerStatus.PREPARING); - player.prepareAsync(); + if (status == PlayerStatus.INITIALIZING) { + if (result != null) { + try { + if (shouldStream) { + player.setDataSource(media + .getStreamUrl()); + setStatus(PlayerStatus.PREPARING); + player.prepareAsync(); + } else { + player.setDataSource(media + .getLocalMediaUrl()); + setStatus(PlayerStatus.PREPARING); + player.prepareAsync(); + } + } catch (IOException e) { + e.printStackTrace(); } - } catch (IOException e) { - e.printStackTrace(); + } else { + setStatus(PlayerStatus.ERROR); + sendBroadcast(new Intent( + ACTION_SHUTDOWN_PLAYBACK_SERVICE)); } - } else { - setStatus(PlayerStatus.ERROR); - sendBroadcast(new Intent( - ACTION_SHUTDOWN_PLAYBACK_SERVICE)); } } @@ -531,35 +542,45 @@ public class PlaybackService extends Service { @Override protected void onPostExecute(Playable result) { - if (result != null) { - playingVideo = false; - try { - if (shouldStream) { - player.setDataSource(media.getStreamUrl()); - } else if (media.localFileAvailable()) { - player.setDataSource(media - .getLocalMediaUrl()); - } + // check if state of service has changed. If it has + // changed, assume that loaded metadata is not needed + // anymore. + if (status == PlayerStatus.INITIALIZING) { + if (result != null) { + playingVideo = false; + try { + if (shouldStream) { + player.setDataSource(media + .getStreamUrl()); + } else if (media.localFileAvailable()) { + player.setDataSource(media + .getLocalMediaUrl()); + } - if (prepareImmediately) { - setStatus(PlayerStatus.PREPARING); - player.prepareAsync(); - } else { - setStatus(PlayerStatus.INITIALIZED); + if (prepareImmediately) { + setStatus(PlayerStatus.PREPARING); + player.prepareAsync(); + } else { + setStatus(PlayerStatus.INITIALIZED); + } + } catch (IOException e) { + e.printStackTrace(); + media = null; + setStatus(PlayerStatus.ERROR); + sendBroadcast(new Intent( + ACTION_SHUTDOWN_PLAYBACK_SERVICE)); } - } catch (IOException e) { - e.printStackTrace(); + } else { + Log.e(TAG, "InitTask could not load metadata"); media = null; setStatus(PlayerStatus.ERROR); sendBroadcast(new Intent( ACTION_SHUTDOWN_PLAYBACK_SERVICE)); } } else { - Log.e(TAG, "InitTask could not load metadata"); - media = null; - setStatus(PlayerStatus.ERROR); - sendBroadcast(new Intent( - ACTION_SHUTDOWN_PLAYBACK_SERVICE)); + if (AppConfig.DEBUG) + Log.d(TAG, + "Status of player has changed during initialization. Stopping init process."); } } @@ -688,7 +709,7 @@ public class PlaybackService extends Service { private void endPlayback(boolean playNextEpisode) { if (AppConfig.DEBUG) - Log.d(TAG, "Playback completed"); + Log.d(TAG, "Playback ended"); audioManager.abandonAudioFocus(audioFocusChangeListener); SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(getApplicationContext()); @@ -1214,6 +1235,22 @@ public class PlaybackService extends Service { }; + private BroadcastReceiver skipCurrentEpisodeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ACTION_SKIP_CURRENT_EPISODE)) { + + if (AppConfig.DEBUG) + Log.d(TAG, "Received SKIP_CURRENT_EPISODE intent"); + if (media != null) { + setStatus(PlayerStatus.STOPPED); + player.reset(); + endPlayback(false); + } + } + } + }; + /** Periodically saves the position of the media file */ class PositionSaver implements Runnable { public static final int WAITING_INTERVALL = 5000; diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java index 9cdf8eec2..d1d0c6966 100644 --- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java +++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java @@ -7,6 +7,7 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.FlattrClickWorker; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedManager; +import de.danoeh.antennapod.service.PlaybackService; import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.ShareUtils; @@ -55,16 +56,22 @@ public class FeedItemMenuHandler { && requester.isDownloadingFile(selectedItem.getMedia()); boolean notLoadedAndNotLoading = hasMedia && (!downloaded) && (!downloading); + boolean isPlaying = hasMedia + && selectedItem.getState() == FeedItem.State.PLAYING; + FeedItem.State state = selectedItem.getState(); - if (!downloaded) { + if (!isPlaying) { + mi.setItemVisibility(R.id.skip_episode_item, false); + } + if (!downloaded || isPlaying) { mi.setItemVisibility(R.id.play_item, false); mi.setItemVisibility(R.id.remove_item, false); } if (!notLoadedAndNotLoading) { mi.setItemVisibility(R.id.download_item, false); } - if (!(notLoadedAndNotLoading | downloading)) { + if (!(notLoadedAndNotLoading | downloading | isPlaying)) { mi.setItemVisibility(R.id.stream_item, false); } if (!downloading) { @@ -104,6 +111,10 @@ public class FeedItemMenuHandler { DownloadRequester requester = DownloadRequester.getInstance(); FeedManager manager = FeedManager.getInstance(); switch (menuItemId) { + case R.id.skip_episode_item: + context.sendBroadcast(new Intent( + PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); + break; case R.id.download_item: manager.downloadFeedItem(context, selectedItem); break; From 1b89523bf75a2c058b68148b94f0496cb131d740 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Fri, 8 Mar 2013 11:18:30 +0100 Subject: [PATCH 10/21] Fixed menu item visibility --- .../danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java index d1d0c6966..c4e6024d3 100644 --- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java +++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java @@ -71,7 +71,7 @@ public class FeedItemMenuHandler { if (!notLoadedAndNotLoading) { mi.setItemVisibility(R.id.download_item, false); } - if (!(notLoadedAndNotLoading | downloading | isPlaying)) { + if (!(notLoadedAndNotLoading | downloading) | isPlaying) { mi.setItemVisibility(R.id.stream_item, false); } if (!downloading) { From 7f81f8a438a9cbb306306d690731678815c6219d Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Fri, 8 Mar 2013 11:43:33 +0100 Subject: [PATCH 11/21] Removed last played media preference --- src/de/danoeh/antennapod/feed/FeedItem.java | 4 +- .../danoeh/antennapod/feed/FeedManager.java | 30 ++-- src/de/danoeh/antennapod/feed/FeedMedia.java | 10 ++ .../preferences/PlaybackPreferences.java | 51 ++----- .../antennapod/service/PlaybackService.java | 129 +++++++----------- .../util/playback/PlaybackController.java | 8 +- 6 files changed, 98 insertions(+), 134 deletions(-) diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java index bb176c411..87cea0a1e 100644 --- a/src/de/danoeh/antennapod/feed/FeedItem.java +++ b/src/de/danoeh/antennapod/feed/FeedItem.java @@ -213,9 +213,7 @@ public class FeedItem extends FeedComponent { private boolean isPlaying() { if (media != null) { - if (PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == media.getId()) { - return true; - } + return media.isPlaying(); } return false; } diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 3203a5e21..19b4a0375 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -157,7 +157,7 @@ public class FeedManager { } } catch (MediaFileNotFoundException e) { e.printStackTrace(); - if (PlaybackPreferences.getLastPlayedId() == media.getId()) { + if (media.isPlaying()) { context.sendBroadcast(new Intent( PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); } @@ -179,14 +179,20 @@ public class FeedManager { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(context); - if (media.getId() == PlaybackPreferences.getLastPlayedId()) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(PlaybackPreferences.PREF_LAST_IS_STREAM, true); - editor.commit(); - } - if (PlaybackPreferences.getLastPlayedId() == media.getId()) { - context.sendBroadcast(new Intent( - PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); + if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) { + if (media.getId() == PlaybackPreferences + .getCurrentlyPlayingFeedMediaId()) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean( + PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM, + true); + editor.commit(); + } + if (PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == media + .getId()) { + context.sendBroadcast(new Intent( + PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); + } } } if (AppConfig.DEBUG) @@ -198,11 +204,11 @@ public class FeedManager { public void deleteFeed(final Context context, final Feed feed) { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(context.getApplicationContext()); - if (PlaybackPreferences.getLastPlayedFeedId() == feed.getId()) { + if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA + && PlaybackPreferences.getLastPlayedFeedId() == feed.getId()) { context.sendBroadcast(new Intent( PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); SharedPreferences.Editor editor = prefs.edit(); - editor.putLong(PlaybackPreferences.PREF_LAST_PLAYED_ID, -1); editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, -1); editor.commit(); @@ -748,7 +754,7 @@ public class FeedManager { .getApplicationContext()); if (UserPreferences.isAutoDelete()) { - if ((media.getId() != PlaybackPreferences.getLastPlayedId()) + if (!media.isPlaying() && ((media.getId() != PlaybackPreferences .getAutoDeleteMediaId()) || (media.getId() == PlaybackPreferences .getAutoDeleteMediaId() && PlaybackPreferences diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java index dbf565535..fd3d2ebb0 100644 --- a/src/de/danoeh/antennapod/feed/FeedMedia.java +++ b/src/de/danoeh/antennapod/feed/FeedMedia.java @@ -8,6 +8,7 @@ import android.content.SharedPreferences.Editor; import android.os.Parcel; import android.os.Parcelable; import de.danoeh.antennapod.PodcastApp; +import de.danoeh.antennapod.preferences.PlaybackPreferences; import de.danoeh.antennapod.util.ChapterUtils; import de.danoeh.antennapod.util.playback.Playable; @@ -103,6 +104,15 @@ public class FeedMedia extends FeedFile implements Playable { return false; } + /** + * Reads playback preferences to determine whether this FeedMedia object is + * currently being played. + */ + public boolean isPlaying() { + return PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA + && PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == id; + } + @Override public int getTypeAsInt() { return FEEDFILETYPE_FEEDMEDIA; diff --git a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java index 82a6df190..22462121a 100644 --- a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java +++ b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java @@ -17,9 +17,6 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "PlaybackPreferences"; - /** Contains the type of the media that was played last. */ - public static final String PREF_LAST_PLAYED_ID = "de.danoeh.antennapod.preferences.lastPlayedId"; - /** * Contains the feed id of the currently playing item if it is a FeedMedia * object. @@ -40,10 +37,10 @@ public class PlaybackPreferences implements public static final String PREF_CURRENTLY_PLAYING_MEDIA = "de.danoeh.antennapod.preferences.currentlyPlayingMedia"; /** True if last played media was streamed. */ - public static final String PREF_LAST_IS_STREAM = "de.danoeh.antennapod.preferences.lastIsStream"; + public static final String PREF_CURRENT_EPISODE_IS_STREAM = "de.danoeh.antennapod.preferences.lastIsStream"; /** True if last played media was a video. */ - public static final String PREF_LAST_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo"; + public static final String PREF_CURRENT_EPISODE_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo"; /** True if playback of last played media has been completed. */ public static final String PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED = "de.danoeh.antennapod.preferences.lastPlaybackCompleted"; @@ -57,12 +54,11 @@ public class PlaybackPreferences implements /** Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing. */ public static final long NO_MEDIA_PLAYING = -1; - private long lastPlayedId; private long currentlyPlayingFeedId; private long currentlyPlayingFeedMediaId; private long currentlyPlayingMedia; - private boolean lastIsStream; - private boolean lastIsVideo; + private boolean currentEpisodeIsStream; + private boolean currentEpisodeIsVideo; private boolean autoDeleteMediaPlaybackCompleted; private long autoDeleteMediaId; @@ -94,14 +90,13 @@ public class PlaybackPreferences implements private void loadPreferences() { SharedPreferences sp = PreferenceManager .getDefaultSharedPreferences(context); - lastPlayedId = sp.getLong(PREF_LAST_PLAYED_ID, -1); currentlyPlayingFeedId = sp.getLong(PREF_CURRENTLY_PLAYING_FEED_ID, -1); currentlyPlayingFeedMediaId = sp.getLong( PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING); currentlyPlayingMedia = sp.getLong(PREF_CURRENTLY_PLAYING_MEDIA, NO_MEDIA_PLAYING); - lastIsStream = sp.getBoolean(PREF_LAST_IS_STREAM, true); - lastIsVideo = sp.getBoolean(PREF_LAST_IS_VIDEO, false); + currentEpisodeIsStream = sp.getBoolean(PREF_CURRENT_EPISODE_IS_STREAM, true); + currentEpisodeIsVideo = sp.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false); autoDeleteMediaPlaybackCompleted = sp.getBoolean( PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, false); autoDeleteMediaId = sp.getLong(PREF_AUTODELETE_MEDIA_ID, -1); @@ -109,18 +104,7 @@ public class PlaybackPreferences implements @Override public void onSharedPreferenceChanged(SharedPreferences sp, String key) { - if (key.equals(PREF_LAST_PLAYED_ID)) { - lastPlayedId = sp.getLong(PREF_LAST_PLAYED_ID, -1); - long mediaId = sp.getLong( - PlaybackPreferences.PREF_AUTODELETE_MEDIA_ID, -1); - if (mediaId != -1) { - FeedManager manager = FeedManager.getInstance(); - FeedMedia media = manager.getFeedMedia(mediaId); - if (media != null) { - manager.autoDeleteIfPossible(context, media); - } - } - } else if (key.equals(PREF_CURRENTLY_PLAYING_FEED_ID)) { + if (key.equals(PREF_CURRENTLY_PLAYING_FEED_ID)) { currentlyPlayingFeedId = sp.getLong(PREF_CURRENTLY_PLAYING_FEED_ID, -1); @@ -128,11 +112,11 @@ public class PlaybackPreferences implements currentlyPlayingMedia = sp .getLong(PREF_CURRENTLY_PLAYING_MEDIA, -1); - } else if (key.equals(PREF_LAST_IS_STREAM)) { - lastIsStream = sp.getBoolean(PREF_LAST_IS_STREAM, true); + } else if (key.equals(PREF_CURRENT_EPISODE_IS_STREAM)) { + currentEpisodeIsStream = sp.getBoolean(PREF_CURRENT_EPISODE_IS_STREAM, true); - } else if (key.equals(PREF_LAST_IS_VIDEO)) { - lastIsVideo = sp.getBoolean(PREF_LAST_IS_VIDEO, false); + } else if (key.equals(PREF_CURRENT_EPISODE_IS_VIDEO)) { + currentEpisodeIsVideo = sp.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false); } else if (key.equals(PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED)) { autoDeleteMediaPlaybackCompleted = sp.getBoolean( @@ -152,11 +136,6 @@ public class PlaybackPreferences implements } } - public static long getLastPlayedId() { - instanceAvailable(); - return instance.lastPlayedId; - } - public static long getAutoDeleteMediaId() { return instance.autoDeleteMediaId; } @@ -175,14 +154,14 @@ public class PlaybackPreferences implements return instance.currentlyPlayingFeedMediaId; } - public static boolean isLastIsStream() { + public static boolean getCurrentEpisodeIsStream() { instanceAvailable(); - return instance.lastIsStream; + return instance.currentEpisodeIsStream; } - public static boolean isLastIsVideo() { + public static boolean getCurrentEpisodeIsVideo() { instanceAvailable(); - return instance.lastIsVideo; + return instance.currentEpisodeIsVideo; } public static boolean isAutoDeleteMediaPlaybackCompleted() { diff --git a/src/de/danoeh/antennapod/service/PlaybackService.java b/src/de/danoeh/antennapod/service/PlaybackService.java index 927413c4d..c596b6938 100644 --- a/src/de/danoeh/antennapod/service/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/PlaybackService.java @@ -179,7 +179,7 @@ public class PlaybackService extends Service { return new Intent(context, AudioplayerActivity.class); } } else { - if (PlaybackPreferences.isLastIsVideo()) { + if (PlaybackPreferences.getCurrentEpisodeIsVideo()) { return new Intent(context, VideoplayerActivity.class); } else { return new Intent(context, AudioplayerActivity.class); @@ -200,35 +200,6 @@ public class PlaybackService extends Service { } } - /** Get last played FeedMedia object or null if it doesn't exist. */ - public static FeedMedia getLastPlayedMediaFromPreferences(Context context) { - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(context.getApplicationContext()); - long mediaId = PlaybackPreferences.getLastPlayedId(); - long feedId = PlaybackPreferences.getLastPlayedFeedId(); - FeedManager manager = FeedManager.getInstance(); - if (mediaId != -1 && feedId != -1) { - Feed feed = manager.getFeed(feedId); - if (feed != null) { - return manager.getFeedMedia(mediaId, feed); - } - } - return null; - } - - private void setLastPlayedMediaId(long mediaId) { - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - long autoDeleteId = PlaybackPreferences.getAutoDeleteMediaId(); - SharedPreferences.Editor editor = prefs.edit(); - if (mediaId == autoDeleteId) { - editor.putBoolean( - PlaybackPreferences.PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, - false); - } - editor.commit(); - } - @SuppressLint("NewApi") @Override public void onCreate() { @@ -272,7 +243,8 @@ public class PlaybackService extends Service { ACTION_SHUTDOWN_PLAYBACK_SERVICE)); registerReceiver(audioBecomingNoisy, new IntentFilter( AudioManager.ACTION_AUDIO_BECOMING_NOISY)); - registerReceiver(skipCurrentEpisodeReceiver, new IntentFilter(ACTION_SKIP_CURRENT_EPISODE)); + registerReceiver(skipCurrentEpisodeReceiver, new IntentFilter( + ACTION_SKIP_CURRENT_EPISODE)); } @@ -711,9 +683,6 @@ public class PlaybackService extends Service { if (AppConfig.DEBUG) Log.d(TAG, "Playback ended"); audioManager.abandonAudioFocus(audioFocusChangeListener); - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()); - SharedPreferences.Editor editor = prefs.edit(); // Save state cancelPositionSaver(); @@ -737,19 +706,7 @@ public class PlaybackService extends Service { if (shouldStream) { autoDeleteMediaId = -1; } - editor.putLong(PlaybackPreferences.PREF_AUTODELETE_MEDIA_ID, - autoDeleteMediaId); } - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.putBoolean( - PlaybackPreferences.PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, - true); - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.commit(); // Load next episode if previous episode was in the queue and if there // is an episode in the queue left. @@ -784,6 +741,7 @@ public class PlaybackService extends Service { } else if (media.getMediaType() == MediaType.VIDEO) { notificationCode = EXTRA_CODE_VIDEO; } + writePlaybackPreferences(); resetVideoSurface(); refreshRemoteControlClientState(); sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, notificationCode); @@ -888,40 +846,8 @@ public class PlaybackService extends Service { Log.d(TAG, "Audiofocus successfully requested"); if (AppConfig.DEBUG) Log.d(TAG, "Resuming/Starting playback"); - SharedPreferences.Editor editor = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()) - .edit(); - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, - media.getPlayableType()); - editor.putBoolean(PlaybackPreferences.PREF_LAST_IS_STREAM, - shouldStream); - editor.putBoolean(PlaybackPreferences.PREF_LAST_IS_VIDEO, - playingVideo); - editor.putLong(PlaybackPreferences.PREF_LAST_PLAYED_ID, - media.getPlayableType()); - if (media instanceof FeedMedia) { - FeedMedia fMedia = (FeedMedia) media; - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, - fMedia.getItem().getFeed().getId()); - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, - fMedia.getId()); - } else { - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, - PlaybackPreferences.NO_MEDIA_PLAYING); - } - media.writeToPreferences(editor); + writePlaybackPreferences(); - editor.commit(); - if (media instanceof FeedMedia) { - setLastPlayedMediaId(((FeedMedia) media).getId()); - } player.start(); if (status != PlayerStatus.PAUSED) { player.seekTo((int) media.getPosition()); @@ -945,6 +871,51 @@ public class PlaybackService extends Service { } } + private void writePlaybackPreferences() { + if (AppConfig.DEBUG) + Log.d(TAG, "Writing playback preferences"); + + SharedPreferences.Editor editor = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()).edit(); + if (media != null) { + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, + media.getPlayableType()); + editor.putBoolean( + PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM, + shouldStream); + editor.putBoolean( + PlaybackPreferences.PREF_CURRENT_EPISODE_IS_VIDEO, + playingVideo); + if (media instanceof FeedMedia) { + FeedMedia fMedia = (FeedMedia) media; + editor.putLong( + PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, + fMedia.getItem().getFeed().getId()); + editor.putLong( + PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, + fMedia.getId()); + } else { + editor.putLong( + PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.putLong( + PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, + PlaybackPreferences.NO_MEDIA_PLAYING); + } + media.writeToPreferences(editor); + } else { + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.putLong( + PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, + PlaybackPreferences.NO_MEDIA_PLAYING); + } + + editor.commit(); + } + private void setStatus(PlayerStatus newStatus) { if (AppConfig.DEBUG) Log.d(TAG, "Setting status to " + newStatus); diff --git a/src/de/danoeh/antennapod/util/playback/PlaybackController.java b/src/de/danoeh/antennapod/util/playback/PlaybackController.java index 699ff6699..ce66ac8ea 100644 --- a/src/de/danoeh/antennapod/util/playback/PlaybackController.java +++ b/src/de/danoeh/antennapod/util/playback/PlaybackController.java @@ -188,9 +188,9 @@ public abstract class PlaybackController { Log.d(TAG, "Trying to restore last played media"); SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(activity.getApplicationContext()); - long lastPlayedId = PlaybackPreferences.getLastPlayedId(); - if (lastPlayedId != PlaybackPreferences.NO_MEDIA_PLAYING) { - Playable media = PlayableUtils.createInstanceFromPreferences((int) lastPlayedId, prefs); + long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia(); + if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) { + Playable media = PlayableUtils.createInstanceFromPreferences((int) currentlyPlayingMedia, prefs); if (media != null) { Intent serviceIntent = new Intent(activity, PlaybackService.class); @@ -200,7 +200,7 @@ public abstract class PlaybackController { serviceIntent.putExtra( PlaybackService.EXTRA_PREPARE_IMMEDIATELY, false); boolean fileExists = media.localFileAvailable(); - boolean lastIsStream = PlaybackPreferences.isLastIsStream(); + boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream(); if (!fileExists && !lastIsStream && media instanceof FeedMedia) { FeedManager.getInstance().notifyMissingFeedMediaFile( activity, (FeedMedia) media); From 3fde2349f9a859fb3b9b95dbf97ff9f7900774c2 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Fri, 8 Mar 2013 20:56:24 +0100 Subject: [PATCH 12/21] Added preferences for configuring auto-download --- AndroidManifest.xml | 1 + res/values/arrays.xml | 8 + res/values/strings.xml | 6 +- res/xml/preferences.xml | 3 + .../activity/PreferenceActivity.java | 142 ++++++++++++++++-- .../preferences/UserPreferences.java | 36 +++++ 6 files changed, 182 insertions(+), 14 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2e6a599f1..3ef1dd204 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -23,6 +23,7 @@ + 24 + + N/A + + + + 0 + + Light Dark diff --git a/res/values/strings.xml b/res/values/strings.xml index a1c9e336a..5c49a5772 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -175,7 +175,11 @@ Delete an episode when playback completes or when it is removed from the queue. Select theme Change the appearance of AntennaPod. - + Automatic download + Configure the automatic download of episodes. + Enable Wi-Fi filter + Allow automatic download only for selected Wi-Fi networks. + Search for Feeds or Episodes Found in shownotes diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index ccde3097f..c409c122e 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -36,6 +36,9 @@ android:summary="@string/pref_mobileUpdate_sum" android:title="@string/pref_mobileUpdate_title" /> + + + networks = wifiservice.getConfiguredNetworks(); + + if (networks != null) { + selectedNetworks = new CheckBoxPreference[networks.size()]; + List prefValues = Arrays.asList(UserPreferences + .getAutodownloadSelectedNetworks()); + PreferenceScreen prefScreen = (PreferenceScreen) findPreference(AUTO_DL_PREF_SCREEN); + OnPreferenceClickListener clickListener = new OnPreferenceClickListener() { + + @Override + public boolean onPreferenceClick(Preference preference) { + if (preference instanceof CheckBoxPreference) { + String key = preference.getKey(); + ArrayList prefValuesList = new ArrayList( + Arrays.asList(UserPreferences + .getAutodownloadSelectedNetworks())); + boolean newValue = ((CheckBoxPreference) preference) + .isChecked(); + if (AppConfig.DEBUG) + Log.d(TAG, "Selected network " + key + + ". New state: " + newValue); + + int index = prefValuesList.indexOf(key); + if (index >= 0 && newValue == false) { + // remove network + prefValuesList.remove(index); + } else if (index < 0 && newValue == true) { + prefValuesList.add(key); + } + + UserPreferences.setAutodownloadSelectedNetworks( + PreferenceActivity.this, prefValuesList + .toArray(new String[prefValuesList + .size()])); + return true; + } else { + return false; + } + } + }; + // create preference for each known network. attach listener and set + // value + for (int i = 0; i < networks.size(); i++) { + WifiConfiguration config = networks.get(i); + + CheckBoxPreference pref = new CheckBoxPreference(this); + String key = Integer.toString(config.networkId); + pref.setTitle(config.SSID); + pref.setKey(key); + pref.setOnPreferenceClickListener(clickListener); + pref.setPersistent(false); + pref.setChecked(prefValues.contains(key)); + selectedNetworks[i] = pref; + prefScreen.addPreference(pref); + } + } else { + Log.e(TAG, "Couldn't get list of configure Wi-Fi networks"); + } + } + + private void clearAutodownloadSelectedNetworsPreference() { + if (selectedNetworks != null) { + PreferenceScreen prefScreen = (PreferenceScreen) findPreference(AUTO_DL_PREF_SCREEN); + + for (int i = 0; i < selectedNetworks.length; i++) { + if (selectedNetworks[i] != null) { + prefScreen.removePreference(selectedNetworks[i]); + } + } + } + } } diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java index f4c0b94b0..72fd7a46a 100644 --- a/src/de/danoeh/antennapod/preferences/UserPreferences.java +++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java @@ -2,8 +2,11 @@ package de.danoeh.antennapod.preferences; import java.io.File; import java.io.IOException; +import java.util.Set; import java.util.concurrent.TimeUnit; +import org.apache.commons.lang3.StringUtils; + import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; @@ -36,6 +39,8 @@ public class UserPreferences implements public static final String PREF_AUTO_DELETE = "prefAutoDelete"; public static final String PREF_THEME = "prefTheme"; public static final String PREF_DATA_FOLDER = "prefDataFolder"; + public static final String PREF_ENABLE_AUTODL_WIFI_FILTER = "prefEnableAutoDownloadWifiFilter"; + private static final String PREF_AUTODL_SELECTED_NETWORKS = "prefAutodownloadSelectedNetworks"; private static UserPreferences instance; private Context context; @@ -50,6 +55,8 @@ public class UserPreferences implements private boolean displayOnlyEpisodes; private boolean autoDelete; private int theme; + private boolean enableAutodownloadWifiFilter; + private String[] autodownloadSelectedNetworks; private UserPreferences(Context context) { this.context = context; @@ -90,6 +97,10 @@ public class UserPreferences implements displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES, false); autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false); theme = readThemeValue(sp.getString(PREF_THEME, "0")); + enableAutodownloadWifiFilter = sp.getBoolean( + PREF_ENABLE_AUTODL_WIFI_FILTER, false); + autodownloadSelectedNetworks = StringUtils.split( + sp.getString(PREF_AUTODL_SELECTED_NETWORKS, ""), ','); } private int readThemeValue(String valueFromPrefs) { @@ -160,6 +171,16 @@ public class UserPreferences implements return instance.theme; } + public static boolean isEnableAutodownloadWifiFilter() { + instanceAvailable(); + return instance.enableAutodownloadWifiFilter; + } + + public static String[] getAutodownloadSelectedNetworks() { + instanceAvailable(); + return instance.autodownloadSelectedNetworks; + } + @Override public void onSharedPreferenceChanged(SharedPreferences sp, String key) { if (AppConfig.DEBUG) @@ -204,9 +225,24 @@ public class UserPreferences implements false); } else if (key.equals(PREF_THEME)) { theme = readThemeValue(sp.getString(PREF_THEME, "")); + } else if (key.equals(PREF_ENABLE_AUTODL_WIFI_FILTER)) { + enableAutodownloadWifiFilter = sp.getBoolean( + PREF_ENABLE_AUTODL_WIFI_FILTER, false); + } else if (key.equals(PREF_AUTODL_SELECTED_NETWORKS)) { + autodownloadSelectedNetworks = StringUtils.split( + sp.getString(PREF_AUTODL_SELECTED_NETWORKS, ""), ','); } } + public static void setAutodownloadSelectedNetworks(Context context, String[] value) { + SharedPreferences.Editor editor = PreferenceManager + .getDefaultSharedPreferences(context.getApplicationContext()) + .edit(); + editor.putString(PREF_AUTODL_SELECTED_NETWORKS, + StringUtils.join(value, ',')); + editor.commit(); + } + /** * Return the folder where the app stores all of its data. This method will * return the standard data folder if none has been set by the user. From 73d23773c5c9517688ba0004914b6d1582ec9f0c Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sat, 9 Mar 2013 11:00:44 +0100 Subject: [PATCH 13/21] Removed auto-delete preference --- res/values/strings.xml | 4 +- res/xml/preferences.xml | 1 - .../danoeh/antennapod/feed/FeedManager.java | 39 ------------------- .../preferences/PlaybackPreferences.java | 27 ------------- 4 files changed, 1 insertion(+), 70 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 5c49a5772..ebd2dfcd8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -171,15 +171,13 @@ Display only episodes Display only items which also have an episode. User Interface - Auto-delete - Delete an episode when playback completes or when it is removed from the queue. Select theme Change the appearance of AntennaPod. Automatic download Configure the automatic download of episodes. Enable Wi-Fi filter Allow automatic download only for selected Wi-Fi networks. - + Search for Feeds or Episodes Found in shownotes diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index c409c122e..ebc020fe5 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -17,7 +17,6 @@ android:key="prefFollowQueue" android:summary="@string/pref_followQueue_sum" android:title="@string/pref_followQueue_title" /> - diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 19b4a0375..ed72f0d47 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -726,7 +726,6 @@ public class FeedManager { public void removeQueueItem(final Context context, FeedItem item) { boolean removed = queue.remove(item); if (removed) { - autoDeleteIfPossible(context, item.getMedia()); dbExec.execute(new Runnable() { @Override @@ -742,44 +741,6 @@ public class FeedManager { eventDist.sendQueueUpdateBroadcast(); } - /** - * Delete the episode of this FeedMedia object if auto-delete is enabled and - * it is not the last played media or it is the last played media and - * playback has been completed. - */ - public void autoDeleteIfPossible(Context context, FeedMedia media) { - if (media != null) { - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(context - .getApplicationContext()); - if (UserPreferences.isAutoDelete()) { - - if (!media.isPlaying() - && ((media.getId() != PlaybackPreferences - .getAutoDeleteMediaId()) || (media.getId() == PlaybackPreferences - .getAutoDeleteMediaId() && PlaybackPreferences - .isAutoDeleteMediaPlaybackCompleted()))) { - if (AppConfig.DEBUG) - Log.d(TAG, "Performing auto-cleanup"); - deleteFeedMedia(context, media); - - SharedPreferences.Editor editor = prefs.edit(); - editor.putLong( - PlaybackPreferences.PREF_AUTODELETE_MEDIA_ID, -1); - editor.commit(); - } else { - if (AppConfig.DEBUG) - Log.d(TAG, "Didn't do auto-cleanup"); - } - } else { - if (AppConfig.DEBUG) - Log.d(TAG, "Auto-delete preference is disabled"); - } - } else { - Log.e(TAG, "Could not do auto-cleanup: media was null"); - } - } - /** * Moves the queue item at the specified index to another position. If the * indices are out of range, no operation will be performed. diff --git a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java index 22462121a..c6a431541 100644 --- a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java +++ b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java @@ -42,15 +42,6 @@ public class PlaybackPreferences implements /** True if last played media was a video. */ public static final String PREF_CURRENT_EPISODE_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo"; - /** True if playback of last played media has been completed. */ - public static final String PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED = "de.danoeh.antennapod.preferences.lastPlaybackCompleted"; - - /** - * ID of the last played media which should be auto-deleted as soon as - * PREF_LAST_PLAYED_ID changes. - */ - public static final String PREF_AUTODELETE_MEDIA_ID = "de.danoeh.antennapod.preferences.autoDeleteMediaId"; - /** Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing. */ public static final long NO_MEDIA_PLAYING = -1; @@ -59,8 +50,6 @@ public class PlaybackPreferences implements private long currentlyPlayingMedia; private boolean currentEpisodeIsStream; private boolean currentEpisodeIsVideo; - private boolean autoDeleteMediaPlaybackCompleted; - private long autoDeleteMediaId; private static PlaybackPreferences instance; private Context context; @@ -97,9 +86,6 @@ public class PlaybackPreferences implements NO_MEDIA_PLAYING); currentEpisodeIsStream = sp.getBoolean(PREF_CURRENT_EPISODE_IS_STREAM, true); currentEpisodeIsVideo = sp.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false); - autoDeleteMediaPlaybackCompleted = sp.getBoolean( - PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, false); - autoDeleteMediaId = sp.getLong(PREF_AUTODELETE_MEDIA_ID, -1); } @Override @@ -118,11 +104,6 @@ public class PlaybackPreferences implements } else if (key.equals(PREF_CURRENT_EPISODE_IS_VIDEO)) { currentEpisodeIsVideo = sp.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false); - } else if (key.equals(PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED)) { - autoDeleteMediaPlaybackCompleted = sp.getBoolean( - PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, false); - } else if (key.equals(PREF_AUTODELETE_MEDIA_ID)) { - autoDeleteMediaId = sp.getLong(PREF_AUTODELETE_MEDIA_ID, -1); } else if (key.equals(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID)) { currentlyPlayingFeedMediaId = sp.getLong( PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING); @@ -136,9 +117,6 @@ public class PlaybackPreferences implements } } - public static long getAutoDeleteMediaId() { - return instance.autoDeleteMediaId; - } public static long getLastPlayedFeedId() { instanceAvailable(); @@ -164,9 +142,4 @@ public class PlaybackPreferences implements return instance.currentEpisodeIsVideo; } - public static boolean isAutoDeleteMediaPlaybackCompleted() { - instanceAvailable(); - return instance.autoDeleteMediaPlaybackCompleted; - } - } From 6a784b7b31cd6de1935cc7ed242c613d6eff0b0c Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sat, 9 Mar 2013 11:13:30 +0100 Subject: [PATCH 14/21] Added episode cache size preference --- res/values/arrays.xml | 9 ++++++++ res/values/strings.xml | 1 + res/xml/preferences.xml | 3 ++- .../activity/PreferenceActivity.java | 21 +++++++++++++++++++ .../preferences/UserPreferences.java | 15 ++++++++++++- 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 6b9650469..aebc74b33 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -21,6 +21,15 @@ 24 + + 10 + 20 + 40 + 60 + 80 + 100 + + N/A diff --git a/res/values/strings.xml b/res/values/strings.xml index ebd2dfcd8..367a91916 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -177,6 +177,7 @@ Configure the automatic download of episodes. Enable Wi-Fi filter Allow automatic download only for selected Wi-Fi networks. + Episode cache Search for Feeds or Episodes diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index ebc020fe5..7f2a4d4bb 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -35,9 +35,10 @@ android:summary="@string/pref_mobileUpdate_sum" android:title="@string/pref_mobileUpdate_title" /> - + + Date: Sat, 9 Mar 2013 11:19:31 +0100 Subject: [PATCH 15/21] Removed auto-queue preference, auto-queue is now always enabled --- res/values/strings.xml | 2 -- res/xml/preferences.xml | 1 - .../antennapod/preferences/UserPreferences.java | 11 ----------- .../antennapod/service/download/DownloadService.java | 3 +-- 4 files changed, 1 insertion(+), 16 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 367a91916..877004162 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -166,8 +166,6 @@ Support the development of AntennaPod by flattring it. Thanks! Revoke access Revoke the access permission to your flattr account for this app. - Auto-enqueue - Add an episode to the queue when you start to download it. Display only episodes Display only items which also have an episode. User Interface diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 7f2a4d4bb..c8c947797 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -34,7 +34,6 @@ android:key="prefMobileUpdate" android:summary="@string/pref_mobileUpdate_sum" android:title="@string/pref_mobileUpdate_title" /> - diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java index 5684c5f37..09fb49623 100644 --- a/src/de/danoeh/antennapod/preferences/UserPreferences.java +++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java @@ -34,7 +34,6 @@ public class UserPreferences implements public static final String PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY = "prefDownloadMediaOnWifiOnly"; public static final String PREF_UPDATE_INTERVAL = "prefAutoUpdateIntervall"; public static final String PREF_MOBILE_UPDATE = "prefMobileUpdate"; - public static final String PREF_AUTO_QUEUE = "prefAutoQueue"; public static final String PREF_DISPLAY_ONLY_EPISODES = "prefDisplayOnlyEpisodes"; public static final String PREF_AUTO_DELETE = "prefAutoDelete"; public static final String PREF_THEME = "prefTheme"; @@ -52,7 +51,6 @@ public class UserPreferences implements private boolean downloadMediaOnWifiOnly; private long updateInterval; private boolean allowMobileUpdate; - private boolean autoQueue; private boolean displayOnlyEpisodes; private boolean autoDelete; private int theme; @@ -95,7 +93,6 @@ public class UserPreferences implements updateInterval = readUpdateInterval(sp.getString(PREF_UPDATE_INTERVAL, "0")); allowMobileUpdate = sp.getBoolean(PREF_MOBILE_UPDATE, false); - autoQueue = sp.getBoolean(PREF_AUTO_QUEUE, true); displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES, false); autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false); theme = readThemeValue(sp.getString(PREF_THEME, "0")); @@ -155,11 +152,6 @@ public class UserPreferences implements return instance.allowMobileUpdate; } - public static boolean isAutoQueue() { - instanceAvailable(); - return instance.autoQueue; - } - public static boolean isDisplayOnlyEpisodes() { instanceAvailable(); return instance.displayOnlyEpisodes; @@ -226,9 +218,6 @@ public class UserPreferences implements } else if (key.equals(PREF_AUTO_DELETE)) { autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false); - } else if (key.equals(PREF_AUTO_QUEUE)) { - autoQueue = sp.getBoolean(PREF_AUTO_QUEUE, true); - } else if (key.equals(PREF_DISPLAY_ONLY_EPISODES)) { displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES, false); diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java index 0aa06985d..d72e3704b 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadService.java +++ b/src/de/danoeh/antennapod/service/download/DownloadService.java @@ -848,8 +848,7 @@ public class DownloadService extends Service { manager.setFeedMedia(DownloadService.this, media); } - if (UserPreferences.isAutoQueue() - && !FeedManager.getInstance().isInQueue(media.getItem())) { + if (!FeedManager.getInstance().isInQueue(media.getItem())) { FeedManager.getInstance().addQueueItem(DownloadService.this, media.getItem()); } From 72ee91e582f545534d6a826265451e199fe28d71 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sat, 9 Mar 2013 14:03:01 +0100 Subject: [PATCH 16/21] Added methods for auto-download and auto-cleanup --- .../danoeh/antennapod/feed/FeedManager.java | 180 +++++++++++++++++- .../danoeh/antennapod/util/NetworkUtils.java | 63 ++++++ 2 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 src/de/danoeh/antennapod/util/NetworkUtils.java diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index ed72f0d47..4fe28a14b 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -29,6 +29,7 @@ import de.danoeh.antennapod.storage.PodDBAdapter; import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.EpisodeFilter; import de.danoeh.antennapod.util.FeedtitleComparator; +import de.danoeh.antennapod.util.NetworkUtils; import de.danoeh.antennapod.util.comparator.DownloadStatusComparator; import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator; import de.danoeh.antennapod.util.comparator.PlaybackCompletionDateComparator; @@ -573,10 +574,26 @@ public class FeedManager { } } - /** Downloads FeedItems if they have not been downloaded yet. */ public void downloadFeedItem(final Context context, FeedItem... items) throws DownloadRequestException { + downloadFeedItem(true, context, items); + } + /** Downloads FeedItems if they have not been downloaded yet. */ + private void downloadFeedItem(boolean performAutoCleanup, + final Context context, final FeedItem... items) + throws DownloadRequestException { + if (performAutoCleanup) { + new Thread() { + + @Override + public void run() { + performAutoCleanup(context, + getPerformAutoCleanupArgs(items.length)); + } + + }.start(); + } for (FeedItem item : items) { if (item.getMedia() != null && !requester.isDownloadingFile(item.getMedia()) @@ -600,6 +617,167 @@ public class FeedManager { } } + /** + * This method will try to download undownloaded items in the queue or the + * unread items list. If not enough space is available, an episode cleanup + * will be performed first. + */ + public void autodownloadUndownloadedItems(Context context) { + if (AppConfig.DEBUG) + Log.d(TAG, "Performing auto-dl of undownloaded episodes"); + if (NetworkUtils.autodownloadNetworkAvailable(context)) { + int undownloadedEpisodes = getNumberOfUndownloadedEpisodes(); + if (undownloadedEpisodes > 0) { + int downloadedEpisodes = getNumberOfDownloadedEpisodes(); + int deletedEpisodes = performAutoCleanup(context, + getPerformAutoCleanupArgs(undownloadedEpisodes)); + int episodeSpaceLeft = undownloadedEpisodes; + if (UserPreferences.getEpisodeCacheSize() < downloadedEpisodes + + undownloadedEpisodes) { + episodeSpaceLeft = UserPreferences.getEpisodeCacheSize() + - (downloadedEpisodes - deletedEpisodes); + } + + List itemsToDownload = new ArrayList(); + if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) { + for (FeedItem item : queue) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + itemsToDownload.add(item); + episodeSpaceLeft--; + undownloadedEpisodes--; + if (episodeSpaceLeft == 0 + || undownloadedEpisodes == 0) { + break; + } + } + } + } + if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) { + for (FeedItem item : unreadItems) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + itemsToDownload.add(item); + episodeSpaceLeft--; + undownloadedEpisodes--; + if (episodeSpaceLeft == 0 + || undownloadedEpisodes == 0) { + break; + } + } + } + } + if (AppConfig.DEBUG) + Log.d(TAG, "Enqueueing " + itemsToDownload.size() + + " items for download"); + + try { + downloadFeedItem(false, context, + itemsToDownload + .toArray(new FeedItem[itemsToDownload + .size()])); + } catch (DownloadRequestException e) { + e.printStackTrace(); + } + + } + + } + } + + /** + * This method will determine the number of episodes that have to be deleted + * depending on a given number of episodes. + * + * @return The argument that has to be passed to performAutoCleanup() so + * that the number of episodes fits into the episode cache. + * */ + private int getPerformAutoCleanupArgs(final int episodeNumber) { + if (episodeNumber >= 0) { + int downloadedEpisodes = getNumberOfDownloadedEpisodes(); + if (downloadedEpisodes + episodeNumber >= UserPreferences + .getEpisodeCacheSize()) { + + return downloadedEpisodes + episodeNumber + - UserPreferences.getEpisodeCacheSize(); + } + } + return 0; + } + + /** + * Performs an auto-cleanup so that the number of downloaded episodes is + * below or equal to the episode cache size. The method will be executed in + * the caller's thread. + */ + public void performAutoCleanup(Context context) { + performAutoCleanup(context, getPerformAutoCleanupArgs(0)); + } + + /** + * This method will try to delete a given number of episodes. An episode + * will only be deleted if it is not in the queue. + * + * @return The number of episodes that were actually deleted + * */ + private int performAutoCleanup(Context context, final int episodeNumber) { + int counter = 0; + int episodesLeft = episodeNumber; + feedloop: for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + if (item.hasMedia() && item.getMedia().isDownloaded()) { + if (!isInQueue(item) && item.isRead()) { + deleteFeedMedia(context, item.getMedia()); + counter++; + episodesLeft--; + if (episodesLeft == 0) { + break feedloop; + } + } + } + } + } + if (AppConfig.DEBUG) + Log.d(TAG, String.format( + "Auto-delete deleted %d episodes (%d requested)", counter, + episodeNumber)); + + return counter; + } + + /** + * Counts items in the queue and the unread items list which haven't been + * downloaded yet. + */ + private int getNumberOfUndownloadedEpisodes() { + int counter = 0; + for (FeedItem item : queue) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + counter++; + } + } + for (FeedItem item : unreadItems) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + counter++; + } + } + return counter; + + } + + /** Counts all downloaded items. */ + private int getNumberOfDownloadedEpisodes() { + int counter = 0; + for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + if (item.hasMedia() && item.getMedia().isDownloaded()) { + counter++; + } + } + } + if (AppConfig.DEBUG) + Log.d(TAG, "Number of downloaded episodes: " + counter); + return counter; + } + /** * Enqueues all items that are currently in the unreadItems list and marks * them as 'read'. diff --git a/src/de/danoeh/antennapod/util/NetworkUtils.java b/src/de/danoeh/antennapod/util/NetworkUtils.java new file mode 100644 index 000000000..6064f3f91 --- /dev/null +++ b/src/de/danoeh/antennapod/util/NetworkUtils.java @@ -0,0 +1,63 @@ +package de.danoeh.antennapod.util; + +import java.util.Arrays; +import java.util.List; + +import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.preferences.UserPreferences; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.util.Log; + +public class NetworkUtils { + private static final String TAG = "NetworkUtils"; + + private NetworkUtils() { + + } + + /** + * Returns true if the device is connected to Wi-Fi and the Wi-Fi filter for + * automatic downloads is disabled or the device is connected to a Wi-Fi + * network that is on the 'selected networks' list of the Wi-Fi filter for + * automatic downloads and false otherwise. + * */ + public static boolean autodownloadNetworkAvailable(Context context) { + ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + if (networkInfo != null) { + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { + if (AppConfig.DEBUG) + Log.d(TAG, "Device is connected to Wi-Fi"); + if (networkInfo.isConnected()) { + if (!UserPreferences.isEnableAutodownloadWifiFilter()) { + if (AppConfig.DEBUG) + Log.d(TAG, "Auto-dl filter is disabled"); + return true; + } else { + WifiManager wm = (WifiManager) context + .getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wm.getConnectionInfo(); + List selectedNetworks = Arrays + .asList(UserPreferences + .getAutodownloadSelectedNetworks()); + if (selectedNetworks.contains(Integer.toString(wifiInfo + .getNetworkId()))) { + if (AppConfig.DEBUG) + Log.d(TAG, + "Current network is on the selected networks list"); + return true; + } + } + } + } + } + if (AppConfig.DEBUG) + Log.d(TAG, "Network for auto-dl is not available"); + return false; + } +} From 485f8905c434f1422728c30bf84c115e74cc502c Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sat, 9 Mar 2013 20:50:53 +0100 Subject: [PATCH 17/21] Added more calls of auto-cleanup and auto-download --- .../danoeh/antennapod/feed/FeedManager.java | 107 ++++++++++-------- 1 file changed, 62 insertions(+), 45 deletions(-) diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 4fe28a14b..e558b34ff 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -627,57 +627,51 @@ public class FeedManager { Log.d(TAG, "Performing auto-dl of undownloaded episodes"); if (NetworkUtils.autodownloadNetworkAvailable(context)) { int undownloadedEpisodes = getNumberOfUndownloadedEpisodes(); - if (undownloadedEpisodes > 0) { - int downloadedEpisodes = getNumberOfDownloadedEpisodes(); - int deletedEpisodes = performAutoCleanup(context, - getPerformAutoCleanupArgs(undownloadedEpisodes)); - int episodeSpaceLeft = undownloadedEpisodes; - if (UserPreferences.getEpisodeCacheSize() < downloadedEpisodes - + undownloadedEpisodes) { - episodeSpaceLeft = UserPreferences.getEpisodeCacheSize() - - (downloadedEpisodes - deletedEpisodes); - } + int downloadedEpisodes = getNumberOfDownloadedEpisodes(); + int deletedEpisodes = performAutoCleanup(context, + getPerformAutoCleanupArgs(undownloadedEpisodes)); + int episodeSpaceLeft = undownloadedEpisodes; + if (UserPreferences.getEpisodeCacheSize() < downloadedEpisodes + + undownloadedEpisodes) { + episodeSpaceLeft = UserPreferences.getEpisodeCacheSize() + - (downloadedEpisodes - deletedEpisodes); + } - List itemsToDownload = new ArrayList(); - if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) { - for (FeedItem item : queue) { - if (item.hasMedia() && !item.getMedia().isDownloaded()) { - itemsToDownload.add(item); - episodeSpaceLeft--; - undownloadedEpisodes--; - if (episodeSpaceLeft == 0 - || undownloadedEpisodes == 0) { - break; - } + List itemsToDownload = new ArrayList(); + if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) { + for (FeedItem item : queue) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + itemsToDownload.add(item); + episodeSpaceLeft--; + undownloadedEpisodes--; + if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) { + break; } } } - if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) { - for (FeedItem item : unreadItems) { - if (item.hasMedia() && !item.getMedia().isDownloaded()) { - itemsToDownload.add(item); - episodeSpaceLeft--; - undownloadedEpisodes--; - if (episodeSpaceLeft == 0 - || undownloadedEpisodes == 0) { - break; - } + } + if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) { + for (FeedItem item : unreadItems) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + itemsToDownload.add(item); + episodeSpaceLeft--; + undownloadedEpisodes--; + if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) { + break; } } } - if (AppConfig.DEBUG) - Log.d(TAG, "Enqueueing " + itemsToDownload.size() - + " items for download"); - - try { - downloadFeedItem(false, context, - itemsToDownload - .toArray(new FeedItem[itemsToDownload - .size()])); - } catch (DownloadRequestException e) { - e.printStackTrace(); - } + } + if (AppConfig.DEBUG) + Log.d(TAG, "Enqueueing " + itemsToDownload.size() + + " items for download"); + try { + downloadFeedItem(false, context, + itemsToDownload.toArray(new FeedItem[itemsToDownload + .size()])); + } catch (DownloadRequestException e) { + e.printStackTrace(); } } @@ -818,6 +812,12 @@ public class FeedManager { adapter.close(); } }); + new Thread() { + @Override + public void run() { + autodownloadUndownloadedItems(context); + } + }.start(); } }); @@ -852,6 +852,12 @@ public class FeedManager { adapter.close(); } }); + new Thread() { + @Override + public void run() { + autodownloadUndownloadedItems(context); + } + }.start(); } }); } @@ -897,7 +903,6 @@ public class FeedManager { if (removed) { adapter.setQueue(queue); } - } /** Removes a FeedItem from the queue. */ @@ -916,6 +921,12 @@ public class FeedManager { }); } + new Thread() { + @Override + public void run() { + autodownloadUndownloadedItems(context); + } + }.start(); eventDist.sendQueueUpdateBroadcast(); } @@ -991,7 +1002,7 @@ public class FeedManager { * * @return The saved Feed with a database ID */ - public Feed updateFeed(Context context, final Feed newFeed) { + public Feed updateFeed(final Context context, final Feed newFeed) { // Look up feed in the feedslist final Feed savedFeed = searchFeedByIdentifyingValue(newFeed .getIdentifyingValue()); @@ -1038,6 +1049,12 @@ public class FeedManager { savedFeed.setLastUpdate(newFeed.getLastUpdate()); savedFeed.setType(newFeed.getType()); setCompleteFeed(context, savedFeed); + new Thread() { + @Override + public void run() { + autodownloadUndownloadedItems(context); + } + }.start(); return savedFeed; } From 6eb08f6693d91da323b57c2790d9abed0a60d182 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sat, 9 Mar 2013 21:08:24 +0100 Subject: [PATCH 18/21] Added Connectivity change receiver --- AndroidManifest.xml | 5 ++ .../receiver/ConnectivityActionReceiver.java | 49 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 3ef1dd204..e319d132e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -348,6 +348,11 @@ android:configChanges="orientation" android:label="@string/organize_queue_label" > + + + + + diff --git a/src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java b/src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java new file mode 100644 index 000000000..5c898384a --- /dev/null +++ b/src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java @@ -0,0 +1,49 @@ +package de.danoeh.antennapod.receiver; + +import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.feed.FeedManager; +import de.danoeh.antennapod.storage.DownloadRequester; +import de.danoeh.antennapod.util.NetworkUtils; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.util.Log; + +public class ConnectivityActionReceiver extends BroadcastReceiver { + private static final String TAG = "ConnectivityActionReceiver"; + + @Override + public void onReceive(final Context context, Intent intent) { + if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + if (AppConfig.DEBUG) + Log.d(TAG, "Received intent"); + + if (NetworkUtils.autodownloadNetworkAvailable(context)) { + if (AppConfig.DEBUG) + Log.d(TAG, + "auto-dl network available, starting auto-download"); + new Thread() { + @Override + public void run() { + FeedManager.getInstance() + .autodownloadUndownloadedItems(context); + } + }.start(); + } else { // if new network is Wi-Fi, finish ongoing downloads, + // otherwise cancel all downloads + ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo ni = cm.getActiveNetworkInfo(); + if (ni == null || ni.getType() != ConnectivityManager.TYPE_WIFI) { + if (AppConfig.DEBUG) + Log.i(TAG, + "Device is no longer connected to Wi-Fi. Cancelling ongoing downloads"); + DownloadRequester.getInstance().cancelAllDownloads(context); + } + + } + } + } +} From aeebcab2020df0aff8b74e153f6d86bbc6c2a5d1 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sat, 9 Mar 2013 21:20:33 +0100 Subject: [PATCH 19/21] Renamed 'new' list to 'waiting list' --- res/values/strings.xml | 1 + .../danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 877004162..5bc40db54 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7,6 +7,7 @@ PODCASTS EPISODES New + Waiting list Settings Add a new Feed Downloads diff --git a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java index 30fcc2fd8..5005b25b4 100644 --- a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java @@ -235,7 +235,7 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { headerString += " (" + getChildrenCount(GROUP_POS_QUEUE) + ")"; } } else { - headerString = context.getString(R.string.new_label); + headerString = context.getString(R.string.waiting_list_label); if (manager.getUnreadItemsSize(true) > 0) { headerString += " (" + getChildrenCount(GROUP_POS_UNREAD) + ")"; } From 3e4fd8e518446ebdb20c8833f942bf968d0dd10f Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sun, 10 Mar 2013 19:27:22 +0100 Subject: [PATCH 20/21] Close media player if no more episodes are available for playback --- .../activity/MediaplayerActivity.java | 5 +++ .../fragment/ExternalPlayerFragment.java | 12 +++++++ .../antennapod/service/PlaybackService.java | 34 +++++++++++++------ .../util/playback/PlaybackController.java | 5 +++ 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java index 10a879c06..6d27a82e0 100644 --- a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -128,6 +128,11 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity public void onShutdownNotification() { finish(); } + + @Override + public void onPlaybackEnd() { + finish(); + } }; } diff --git a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java index 94aa2b0fc..1b7d77193 100644 --- a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -162,6 +162,18 @@ public class ExternalPlayerFragment extends SherlockFragment { } } + + @Override + public void onPlaybackEnd() { + if (fragmentLayout != null) { + fragmentLayout.setVisibility(View.GONE); + } + controller = setupPlaybackController(); + if (butPlay != null) { + butPlay.setOnClickListener(controller + .newOnPlayButtonClickListener()); + } + } }; } diff --git a/src/de/danoeh/antennapod/service/PlaybackService.java b/src/de/danoeh/antennapod/service/PlaybackService.java index c596b6938..811b02535 100644 --- a/src/de/danoeh/antennapod/service/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/PlaybackService.java @@ -103,6 +103,8 @@ public class PlaybackService extends Service { public static final int NOTIFICATION_TYPE_SLEEPTIMER_UPDATE = 4; public static final int NOTIFICATION_TYPE_BUFFER_START = 5; public static final int NOTIFICATION_TYPE_BUFFER_END = 6; + /** No more episodes are going to be played. */ + public static final int NOTIFICATION_TYPE_PLAYBACK_END = 7; /** * Returned by getPositionSafe() or getDurationSafe() if the playbackService @@ -493,7 +495,9 @@ public class PlaybackService extends Service { player.release(); player = createMediaPlayer(); status = PlayerStatus.STOPPED; - initMediaplayer(); + if (media != null) { + initMediaplayer(); + } } public void notifyVideoSurfaceAbandoned() { @@ -727,24 +731,32 @@ public class PlaybackService extends Service { } else { if (AppConfig.DEBUG) Log.d(TAG, - "No more episodes available to play; Reloading current episode"); + "No more episodes available to play"); + media = null; prepareImmediately = startWhenPrepared = false; stopForeground(true); stopWidgetUpdater(); } int notificationCode = 0; - shouldStream = !media.localFileAvailable(); - if (media.getMediaType() == MediaType.AUDIO) { - notificationCode = EXTRA_CODE_AUDIO; - playingVideo = false; - } else if (media.getMediaType() == MediaType.VIDEO) { - notificationCode = EXTRA_CODE_VIDEO; + if (media != null) { + shouldStream = !media.localFileAvailable(); + if (media.getMediaType() == MediaType.AUDIO) { + notificationCode = EXTRA_CODE_AUDIO; + playingVideo = false; + } else if (media.getMediaType() == MediaType.VIDEO) { + notificationCode = EXTRA_CODE_VIDEO; + } } writePlaybackPreferences(); - resetVideoSurface(); - refreshRemoteControlClientState(); - sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, notificationCode); + if (media != null) { + resetVideoSurface(); + refreshRemoteControlClientState(); + sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, notificationCode); + } else { + sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0); + stopSelf(); + } } public void setSleepTimer(long waitingTime) { diff --git a/src/de/danoeh/antennapod/util/playback/PlaybackController.java b/src/de/danoeh/antennapod/util/playback/PlaybackController.java index ce66ac8ea..331e2bf0c 100644 --- a/src/de/danoeh/antennapod/util/playback/PlaybackController.java +++ b/src/de/danoeh/antennapod/util/playback/PlaybackController.java @@ -320,6 +320,9 @@ public abstract class PlaybackController { case PlaybackService.NOTIFICATION_TYPE_BUFFER_END: onBufferEnd(); break; + case PlaybackService.NOTIFICATION_TYPE_PLAYBACK_END: + onPlaybackEnd(); + break; } } else { @@ -357,6 +360,8 @@ public abstract class PlaybackController { public abstract void onSleepTimerUpdate(); public abstract void handleError(int code); + + public abstract void onPlaybackEnd(); /** * Is called whenever the PlaybackService changes it's status. This method From d4b7acd5df4e6a6ecc04923dd629978244d21b13 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Sun, 10 Mar 2013 19:30:39 +0100 Subject: [PATCH 21/21] Hide 'mark as unread' when not in debug mode --- .../antennapod/util/menuhandler/FeedItemMenuHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java index c4e6024d3..b1bc5a8e2 100644 --- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java +++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod.util.menuhandler; import android.content.Context; import android.content.Intent; import android.net.Uri; +import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.FlattrClickWorker; import de.danoeh.antennapod.feed.FeedItem; @@ -89,7 +90,8 @@ public class FeedItemMenuHandler { mi.setItemVisibility(R.id.share_link_item, false); } - if (!(state == FeedItem.State.IN_PROGRESS || state == FeedItem.State.READ)) { + if (!AppConfig.DEBUG + || !(state == FeedItem.State.IN_PROGRESS || state == FeedItem.State.READ)) { mi.setItemVisibility(R.id.mark_unread_item, false); } if (!(state == FeedItem.State.NEW || state == FeedItem.State.IN_PROGRESS)) {