summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/de/danoeh/antennapod/activity/MediaplayerActivity.java11
-rw-r--r--src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java27
-rw-r--r--src/de/danoeh/antennapod/activity/PreferenceActivity.java163
-rw-r--r--src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java59
-rw-r--r--src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java52
-rw-r--r--src/de/danoeh/antennapod/feed/FeedItem.java4
-rw-r--r--src/de/danoeh/antennapod/feed/FeedManager.java340
-rw-r--r--src/de/danoeh/antennapod/feed/FeedMedia.java14
-rw-r--r--src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java12
-rw-r--r--src/de/danoeh/antennapod/preferences/PlaybackPreferences.java78
-rw-r--r--src/de/danoeh/antennapod/preferences/UserPreferences.java60
-rw-r--r--src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java49
-rw-r--r--src/de/danoeh/antennapod/service/PlaybackService.java379
-rw-r--r--src/de/danoeh/antennapod/service/download/DownloadService.java8
-rw-r--r--src/de/danoeh/antennapod/util/NetworkUtils.java63
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java19
-rw-r--r--src/de/danoeh/antennapod/util/playback/PlaybackController.java13
17 files changed, 964 insertions, 387 deletions
diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
index c217a4628..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();
+ }
};
}
@@ -227,7 +232,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 +308,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/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/activity/PreferenceActivity.java b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
index 360ff610d..6bad316a6 100644
--- a/src/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -1,13 +1,22 @@
package de.danoeh.antennapod.activity;
import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.res.Resources.Theme;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
import android.os.Bundle;
+import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceScreen;
import android.util.Log;
import com.actionbarsherlock.app.SherlockPreferenceActivity;
@@ -32,6 +41,9 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
private static final String PREF_OPML_EXPORT = "prefOpmlExport";
private static final String PREF_ABOUT = "prefAbout";
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
+ private static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings";
+
+ private CheckBoxPreference[] selectedNetworks;
@SuppressWarnings("deprecation")
@Override
@@ -102,27 +114,69 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
return true;
}
});
- findPreference(UserPreferences.PREF_THEME).setOnPreferenceChangeListener(
- new OnPreferenceChangeListener() {
+ findPreference(UserPreferences.PREF_THEME)
+ .setOnPreferenceChangeListener(
+ new OnPreferenceChangeListener() {
+
+ @Override
+ public boolean onPreferenceChange(
+ Preference preference, Object newValue) {
+ Intent i = getIntent();
+ i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
+ | Intent.FLAG_ACTIVITY_NEW_TASK);
+ finish();
+ startActivity(i);
+ return true;
+ }
+ });
+ findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
+ .setOnPreferenceChangeListener(
+ new OnPreferenceChangeListener() {
+
+ @Override
+ public boolean onPreferenceChange(
+ Preference preference, Object newValue) {
+ if (newValue instanceof Boolean) {
+ setSelectedNetworksEnabled((Boolean) newValue);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ });
+ findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
+ .setOnPreferenceChangeListener(
+ new OnPreferenceChangeListener() {
+
+ @Override
+ public boolean onPreferenceChange(
+ Preference preference, Object newValue) {
+ if (newValue instanceof String) {
+ setEpisodeCacheSizeText(Integer
+ .valueOf((String) newValue));
+ }
+ return true;
+ }
+ });
+ buildAutodownloadSelectedNetworsPreference();
+ setSelectedNetworksEnabled(UserPreferences
+ .isEnableAutodownloadWifiFilter());
- @Override
- public boolean onPreferenceChange(Preference preference,
- Object newValue) {
- Intent i = getIntent();
- i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
- | Intent.FLAG_ACTIVITY_NEW_TASK);
- finish();
- startActivity(i);
- return true;
- }
- });
+ }
+ private void setSelectedNetworksEnabled(boolean b) {
+ if (selectedNetworks != null) {
+ for (Preference p : selectedNetworks) {
+ p.setEnabled(b);
+ }
+ }
}
@Override
protected void onResume() {
super.onResume();
checkItemVisibility();
+ setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
setDataFolderText();
}
@@ -136,6 +190,12 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
}
+ private void setEpisodeCacheSizeText(int cacheSize) {
+ findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setSummary(
+ Integer.toString(cacheSize)
+ + getString(R.string.episodes_suffix));
+ }
+
private void setDataFolderText() {
File f = UserPreferences.getDataFolder(this, null);
if (f != null) {
@@ -180,4 +240,81 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
}
}
+ private void buildAutodownloadSelectedNetworsPreference() {
+ if (selectedNetworks != null) {
+ clearAutodownloadSelectedNetworsPreference();
+ }
+ // get configured networks
+ WifiManager wifiservice = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ List<WifiConfiguration> networks = wifiservice.getConfiguredNetworks();
+
+ if (networks != null) {
+ selectedNetworks = new CheckBoxPreference[networks.size()];
+ List<String> 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<String> prefValuesList = new ArrayList<String>(
+ 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<FeedItem> addToQueue = new ArrayList<FeedItem>();
+ 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,16 +613,166 @@ 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<FeedItem> itemsToDownload = new ArrayList<FeedItem>();
+ 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;
}
@@ -1521,6 +1723,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.
*
* @param enableEpisodeFilter
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() {
- instanceAvailable();
- return instance.lastIsStream;
- }
-
- public static boolean isLastIsVideo() {
+ public static boolean getCurrentEpisodeIsStream() {
instanceAvailable();
- return instance.lastIsVideo;
+ return instance.currentEpisodeIsStream;
}
- public static boolean isAutoDeleteMediaPlaybackCompleted() {
+ public static boolean getCurrentEpisodeIsVideo() {
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());
- }
-
- if (prepareImmediately) {
- setStatus(PlayerStatus.PREPARING);
- player.prepareAsync();
- } else {
- setStatus(PlayerStatus.INITIALIZED);
+ // 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);
+ }
+ } 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,89 +670,94 @@ 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();
+ endPlayback(true);
+ }
+ };
- // Save state
- cancelPositionSaver();
+ private MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
- boolean isInQueue = false;
- FeedItem nextItem = null;
+ @Override
+ public void onBufferingUpdate(MediaPlayer mp, int percent) {
+ sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_UPDATE, percent);
- 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();
+ 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;
}
- int notificationCode = 0;
+ }
+
+ // 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);
- }
- };
-
- private MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
-
- @Override
- public void onBufferingUpdate(MediaPlayer mp, int percent) {
- sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_UPDATE, percent);
-
+ sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, notificationCode);
+ } else {
+ sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0);
+ stopSelf();
}
- };
+ }
public void setSleepTimer(long waitingTime) {
if (AppConfig.DEBUG)
@@ -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<String> 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