diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2e6a599f1..e319d132e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -23,6 +23,7 @@ + + + + + + diff --git a/res/layout/external_itemlist_item.xml b/res/layout/external_itemlist_item.xml index fe1c29a19..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,21 +81,15 @@ 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/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/arrays.xml b/res/values/arrays.xml index 17a94c29f..aebc74b33 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -21,6 +21,23 @@ 24 + + 10 + 20 + 40 + 60 + 80 + 100 + + + + N/A + + + + 0 + + Light Dark 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..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 @@ -70,6 +71,7 @@ Flattr this Enqueue all Download all + Skip episode Download successful @@ -165,15 +167,16 @@ 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 - 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. + Episode cache Search for Feeds or Episodes diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index ccde3097f..c8c947797 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" /> - @@ -35,7 +34,10 @@ android:key="prefMobileUpdate" 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/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java index db716c66e..5005b25b4 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,10 +90,8 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { .findViewById(R.id.butAction); holder.statusPlaying = (View) convertView .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 { holder = (Holder) convertView.getTag(); @@ -100,41 +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.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; } } else { holder.statusPlaying.setVisibility(View.GONE); - holder.statusUnread.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); @@ -144,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); } @@ -188,9 +194,8 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { ImageView downloadStatus; ImageView feedImage; ImageButton butAction; - View statusUnread; View statusPlaying; - TextView statusInProgress; + ProgressBar episodeProgress; } @Override @@ -230,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) + ")"; } 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() { 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 e984da46a..e558b34ff 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; @@ -111,7 +112,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,9 +151,14 @@ 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()) { + if (media.isPlaying()) { context.sendBroadcast(new Intent( PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); } @@ -173,14 +180,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) @@ -192,12 +205,13 @@ 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.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, + -1); editor.commit(); } @@ -560,11 +574,26 @@ 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(); + 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()) @@ -584,15 +613,165 @@ public class FeedManager { } else { requester.downloadMedia(context, item.getMedia()); } - addToQueue.add(item); } } - if (UserPreferences.isAutoQueue()) { - addQueueItem(context, - addToQueue.toArray(new FeedItem[addToQueue.size()])); + } + + /** + * 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(); + 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'. @@ -605,7 +784,49 @@ 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(); + } + }); + new Thread() { + @Override + public void run() { + autodownloadUndownloadedItems(context); + } + }.start(); + } + }); + + } + + /** + * 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 +836,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(); @@ -628,6 +852,12 @@ public class FeedManager { adapter.close(); } }); + new Thread() { + @Override + public void run() { + autodownloadUndownloadedItems(context); + } + }.start(); } }); } @@ -673,14 +903,12 @@ public class FeedManager { if (removed) { adapter.setQueue(queue); } - } /** Removes a FeedItem from the queue. */ public void removeQueueItem(final Context context, FeedItem item) { boolean removed = queue.remove(item); if (removed) { - autoDeleteIfPossible(context, item.getMedia()); dbExec.execute(new Runnable() { @Override @@ -693,45 +921,13 @@ 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.getId() != PlaybackPreferences.getLastPlayedId()) - && ((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"); + new Thread() { + @Override + public void run() { + autodownloadUndownloadedItems(context); } - } else { - Log.e(TAG, "Could not do auto-cleanup: media was null"); - } + }.start(); + eventDist.sendQueueUpdateBroadcast(); } /** @@ -806,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()); @@ -853,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; } @@ -1520,6 +1722,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. * diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java index de87c63a1..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; @@ -257,10 +267,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 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/preferences/PlaybackPreferences.java b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java index b93b2e07c..c6a431541 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,31 +37,19 @@ 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"; - - /** 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"; + public static final String PREF_CURRENT_EPISODE_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo"; /** 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 autoDeleteMediaPlaybackCompleted; - private long autoDeleteMediaId; + private boolean currentEpisodeIsStream; + private boolean currentEpisodeIsVideo; private static PlaybackPreferences instance; private Context context; @@ -94,33 +79,18 @@ 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); - autoDeleteMediaPlaybackCompleted = sp.getBoolean( - PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, false); - autoDeleteMediaId = sp.getLong(PREF_AUTODELETE_MEDIA_ID, -1); + currentEpisodeIsStream = sp.getBoolean(PREF_CURRENT_EPISODE_IS_STREAM, true); + currentEpisodeIsVideo = sp.getBoolean(PREF_CURRENT_EPISODE_IS_VIDEO, false); } @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,17 +98,12 @@ 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( - PREF_AUTODELETE_MEDIA_ID, 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); @@ -152,14 +117,6 @@ public class PlaybackPreferences implements } } - public static long getLastPlayedId() { - instanceAvailable(); - return instance.lastPlayedId; - } - - public static long getAutoDeleteMediaId() { - return instance.autoDeleteMediaId; - } public static long getLastPlayedFeedId() { instanceAvailable(); @@ -175,19 +132,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; - } - - public static boolean isAutoDeleteMediaPlaybackCompleted() { - instanceAvailable(); - return instance.autoDeleteMediaPlaybackCompleted; + return instance.currentEpisodeIsVideo; } } diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java index f4c0b94b0..09fb49623 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; @@ -31,11 +34,13 @@ 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"; 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"; + public static final String PREF_EPISODE_CACHE_SIZE = "prefEpisodeCacheSize"; private static UserPreferences instance; private Context context; @@ -46,10 +51,12 @@ 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; + private boolean enableAutodownloadWifiFilter; + private String[] autodownloadSelectedNetworks; + private int episodeCacheSize; private UserPreferences(Context context) { this.context = context; @@ -86,10 +93,15 @@ 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")); + enableAutodownloadWifiFilter = sp.getBoolean( + PREF_ENABLE_AUTODL_WIFI_FILTER, false); + autodownloadSelectedNetworks = StringUtils.split( + sp.getString(PREF_AUTODL_SELECTED_NETWORKS, ""), ','); + episodeCacheSize = Integer.valueOf(sp.getString( + PREF_EPISODE_CACHE_SIZE, "20")); } private int readThemeValue(String valueFromPrefs) { @@ -140,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; @@ -160,6 +167,21 @@ public class UserPreferences implements return instance.theme; } + public static boolean isEnableAutodownloadWifiFilter() { + instanceAvailable(); + return instance.enableAutodownloadWifiFilter; + } + + public static String[] getAutodownloadSelectedNetworks() { + instanceAvailable(); + return instance.autodownloadSelectedNetworks; + } + + public static int getEpisodeCacheSize() { + instanceAvailable(); + return instance.episodeCacheSize; + } + @Override public void onSharedPreferenceChanged(SharedPreferences sp, String key) { if (AppConfig.DEBUG) @@ -196,17 +218,33 @@ 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); } 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, ""), ','); + } else if (key.equals(PREF_EPISODE_CACHE_SIZE)) { + episodeCacheSize = Integer.valueOf(sp.getString( + PREF_EPISODE_CACHE_SIZE, "20")); } } + 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. 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); + } + + } + } + } +} diff --git a/src/de/danoeh/antennapod/service/PlaybackService.java b/src/de/danoeh/antennapod/service/PlaybackService.java index 450f7f65d..811b02535 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; @@ -97,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 @@ -173,7 +181,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); @@ -194,35 +202,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() { @@ -266,6 +245,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)); } @@ -296,6 +277,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 +442,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)); } } @@ -510,7 +495,9 @@ public class PlaybackService extends Service { player.release(); player = createMediaPlayer(); status = PlayerStatus.STOPPED; - initMediaplayer(); + if (media != null) { + initMediaplayer(); + } } public void notifyVideoSurfaceAbandoned() { @@ -531,35 +518,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."); } } @@ -673,78 +670,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 +683,82 @@ public class PlaybackService extends Service { } }; + private void endPlayback(boolean playNextEpisode) { + if (AppConfig.DEBUG) + Log.d(TAG, "Playback ended"); + audioManager.abandonAudioFocus(audioFocusChangeListener); + + // 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; + } + } + + // 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"); + media = null; + prepareImmediately = startWhenPrepared = false; + stopForeground(true); + stopWidgetUpdater(); + } + + int notificationCode = 0; + 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(); + if (media != null) { + resetVideoSurface(); + refreshRemoteControlClientState(); + sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, notificationCode); + } else { + sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0); + stopSelf(); + } + } + public void setSleepTimer(long waitingTime) { if (AppConfig.DEBUG) Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime) @@ -856,40 +858,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()); @@ -913,6 +883,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); @@ -1005,7 +1020,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(); @@ -1201,6 +1218,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/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java index 986491fb5..d72e3704b 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,11 @@ public class DownloadService extends Service { manager.setFeedMedia(DownloadService.this, media); } + if (!FeedManager.getInstance().isInQueue(media.getItem())) { + FeedManager.getInstance().addQueueItem(DownloadService.this, + media.getItem()); + } + downloadsBeingHandled -= 1; handler.post(new Runnable() { 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; + } +} diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java index 9cdf8eec2..b1bc5a8e2 100644 --- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java +++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java @@ -3,10 +3,12 @@ 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; 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 +57,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) { @@ -82,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)) { @@ -104,6 +113,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; diff --git a/src/de/danoeh/antennapod/util/playback/PlaybackController.java b/src/de/danoeh/antennapod/util/playback/PlaybackController.java index 699ff6699..331e2bf0c 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); @@ -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