summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordaniel oeh <daniel.oeh@gmail.com>2014-06-14 14:09:52 +0200
committerdaniel oeh <daniel.oeh@gmail.com>2014-06-14 14:30:17 +0200
commit1673f6eaf83606a78ce3928b2d7c33d4ff0de862 (patch)
tree2f31961d0f389f8bebe04ba10473317d9881c97b /src
parentb2ae4c15d13840619fb09cc141b290449e40a6a4 (diff)
parent7aa0d3be100c4d7cc79c3a71000378975ae96c8b (diff)
downloadAntennaPod-1673f6eaf83606a78ce3928b2d7c33d4ff0de862.zip
Merge branch 'develop'0.9.9.1
Diffstat (limited to 'src')
-rw-r--r--src/de/danoeh/antennapod/AppConfig.java3
-rw-r--r--src/de/danoeh/antennapod/activity/AudioplayerActivity.java34
-rw-r--r--src/de/danoeh/antennapod/activity/FeedInfoActivity.java1
-rw-r--r--src/de/danoeh/antennapod/activity/MainActivity.java53
-rw-r--r--src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java66
-rw-r--r--src/de/danoeh/antennapod/activity/PreferenceActivity.java74
-rw-r--r--src/de/danoeh/antennapod/adapter/AdapterUtils.java57
-rw-r--r--src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java25
-rw-r--r--src/de/danoeh/antennapod/adapter/FeedlistAdapter.java174
-rw-r--r--src/de/danoeh/antennapod/adapter/NavListAdapter.java31
-rw-r--r--src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java7
-rw-r--r--src/de/danoeh/antennapod/adapter/QueueListAdapter.java17
-rw-r--r--src/de/danoeh/antennapod/asynctask/ImageDiskCache.java8
-rw-r--r--src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java28
-rw-r--r--src/de/danoeh/antennapod/service/download/DownloadService.java1
-rw-r--r--src/de/danoeh/antennapod/service/playback/PlaybackService.java1
-rw-r--r--src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java36
-rw-r--r--src/de/danoeh/antennapod/storage/DBReader.java48
-rw-r--r--src/de/danoeh/antennapod/storage/PodDBAdapter.java12
-rw-r--r--src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java11
-rw-r--r--src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java40
-rw-r--r--src/instrumentationTest/de/test/antennapod/ui/MainActivityTest.java118
-rw-r--r--src/instrumentationTest/de/test/antennapod/ui/PlaybackTest.java149
-rw-r--r--src/instrumentationTest/de/test/antennapod/ui/UITestUtils.java194
-rw-r--r--src/instrumentationTest/de/test/antennapod/ui/UITestUtilsTest.java94
-rw-r--r--src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java4
26 files changed, 950 insertions, 336 deletions
diff --git a/src/de/danoeh/antennapod/AppConfig.java b/src/de/danoeh/antennapod/AppConfig.java
index 1f55e73a6..cac946f84 100644
--- a/src/de/danoeh/antennapod/AppConfig.java
+++ b/src/de/danoeh/antennapod/AppConfig.java
@@ -2,5 +2,6 @@ package de.danoeh.antennapod;
public final class AppConfig {
/** Should be used when setting User-Agent header for HTTP-requests. */
- public final static String USER_AGENT = "AntennaPod/0.9.9.0";
+ public final static String USER_AGENT = "AntennaPod/0.9.9.1";
+
}
diff --git a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 2ffaae967..090c3f1f5 100644
--- a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -34,8 +34,6 @@ import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.util.playback.ExternalMedia;
import de.danoeh.antennapod.util.playback.Playable;
-import java.util.List;
-
/**
* Activity for playing audio files.
*/
@@ -624,20 +622,20 @@ public class AudioplayerActivity extends MediaplayerActivity {
}
}
- private List<Feed> feeds;
- private AsyncTask<Void, Void, List<Feed>> loadTask;
+ private DBReader.NavDrawerData navDrawerData;
+ private AsyncTask<Void, Void, DBReader.NavDrawerData> loadTask;
private void loadData() {
- loadTask = new AsyncTask<Void, Void, List<Feed>>() {
+ loadTask = new AsyncTask<Void, Void, DBReader.NavDrawerData>() {
@Override
- protected List<Feed> doInBackground(Void... params) {
- return DBReader.getFeedList(AudioplayerActivity.this);
+ protected DBReader.NavDrawerData doInBackground(Void... params) {
+ return DBReader.getNavDrawerData(AudioplayerActivity.this);
}
@Override
- protected void onPostExecute(List<Feed> result) {
+ protected void onPostExecute(DBReader.NavDrawerData result) {
super.onPostExecute(result);
- feeds = result;
+ navDrawerData = result;
if (navAdapter != null) {
navAdapter.notifyDataSetChanged();
}
@@ -667,8 +665,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
@Override
public int getCount() {
- if (feeds != null) {
- return feeds.size();
+ if (navDrawerData != null) {
+ return navDrawerData.feeds.size();
} else {
return 0;
}
@@ -676,8 +674,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
public Feed getItem(int position) {
- if (feeds != null && position < feeds.size()) {
- return feeds.get(position);
+ if (navDrawerData != null && position < navDrawerData.feeds.size()) {
+ return navDrawerData.feeds.get(position);
} else {
return null;
}
@@ -687,5 +685,15 @@ public class AudioplayerActivity extends MediaplayerActivity {
public int getSelectedItemIndex() {
return -1;
}
+
+ @Override
+ public int getQueueSize() {
+ return (navDrawerData != null) ? navDrawerData.queueSize : 0;
+ }
+
+ @Override
+ public int getNumberOfUnreadItems() {
+ return (navDrawerData != null) ? navDrawerData.numUnreadItems : 0;
+ }
};
}
diff --git a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
index f00ce13e8..7f60d0b10 100644
--- a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -166,6 +166,7 @@ public class FeedInfoActivity extends ActionBarActivity {
menu.findItem(R.id.support_item).setVisible(
feed != null && feed.getPaymentLink() != null);
menu.findItem(R.id.share_link_item).setVisible(feed != null &&feed.getLink() != null);
+ menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null);
return true;
}
diff --git a/src/de/danoeh/antennapod/activity/MainActivity.java b/src/de/danoeh/antennapod/activity/MainActivity.java
index 92afea77c..257bea82d 100644
--- a/src/de/danoeh/antennapod/activity/MainActivity.java
+++ b/src/de/danoeh/antennapod/activity/MainActivity.java
@@ -39,10 +39,11 @@ public class MainActivity extends ActionBarActivity {
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
| EventDistributor.DOWNLOAD_QUEUED
| EventDistributor.FEED_LIST_UPDATE
- | EventDistributor.UNREAD_ITEMS_UPDATE;
+ | EventDistributor.UNREAD_ITEMS_UPDATE
+ | EventDistributor.QUEUE_UPDATE;
- private static final String PREF_NAME = "MainActivityPrefs";
- private static final String PREF_IS_FIRST_LAUNCH = "prefMainActivityIsFirstLaunch";
+ public static final String PREF_NAME = "MainActivityPrefs";
+ public static final String PREF_IS_FIRST_LAUNCH = "prefMainActivityIsFirstLaunch";
public static final String EXTRA_NAV_INDEX = "nav_index";
public static final String EXTRA_NAV_TYPE = "nav_type";
@@ -147,7 +148,7 @@ public class MainActivity extends ActionBarActivity {
}
public List<Feed> getFeeds() {
- return feeds;
+ return (navDrawerData != null) ? navDrawerData.feeds : null;
}
private void loadFragment(int viewType, int relPos, Bundle args) {
@@ -207,9 +208,9 @@ public class MainActivity extends ActionBarActivity {
}
public void loadFeedFragment(long feedID) {
- if (feeds != null) {
- for (int i = 0; i < feeds.size(); i++) {
- if (feeds.get(i).getId() == feedID) {
+ if (navDrawerData != null) {
+ for (int i = 0; i < navDrawerData.feeds.size(); i++) {
+ if (navDrawerData.feeds.get(i).getId() == feedID) {
loadFragment(NavListAdapter.VIEW_TYPE_SUBSCRIPTION, i, null);
break;
}
@@ -279,7 +280,7 @@ public class MainActivity extends ActionBarActivity {
EventDistributor.getInstance().register(contentUpdate);
Intent intent = getIntent();
- if (feeds != null && intent.hasExtra(EXTRA_NAV_INDEX) && intent.hasExtra(EXTRA_NAV_TYPE)) {
+ if (navDrawerData != null && intent.hasExtra(EXTRA_NAV_INDEX) && intent.hasExtra(EXTRA_NAV_TYPE)) {
handleNavIntent();
}
@@ -322,15 +323,15 @@ public class MainActivity extends ActionBarActivity {
return true;
}
- private List<Feed> feeds;
- private AsyncTask<Void, Void, List<Feed>> loadTask;
+ private DBReader.NavDrawerData navDrawerData;
+ private AsyncTask<Void, Void, DBReader.NavDrawerData> loadTask;
private int selectedNavListIndex = 0;
private NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
@Override
public int getCount() {
- if (feeds != null) {
- return feeds.size();
+ if (navDrawerData != null) {
+ return navDrawerData.feeds.size();
} else {
return 0;
}
@@ -338,8 +339,8 @@ public class MainActivity extends ActionBarActivity {
@Override
public Feed getItem(int position) {
- if (feeds != null && position < feeds.size()) {
- return feeds.get(position);
+ if (navDrawerData != null && position < navDrawerData.feeds.size()) {
+ return navDrawerData.feeds.get(position);
} else {
return null;
}
@@ -350,23 +351,33 @@ public class MainActivity extends ActionBarActivity {
return selectedNavListIndex;
}
+ @Override
+ public int getQueueSize() {
+ return (navDrawerData != null) ? navDrawerData.queueSize : 0;
+ }
+
+ @Override
+ public int getNumberOfUnreadItems() {
+ return (navDrawerData != null) ? navDrawerData.numUnreadItems : 0;
+ }
+
};
private void loadData() {
cancelLoadTask();
- loadTask = new AsyncTask<Void, Void, List<Feed>>() {
+ loadTask = new AsyncTask<Void, Void, DBReader.NavDrawerData>() {
@Override
- protected List<Feed> doInBackground(Void... params) {
- return DBReader.getFeedList(MainActivity.this);
+ protected DBReader.NavDrawerData doInBackground(Void... params) {
+ return DBReader.getNavDrawerData(MainActivity.this);
}
@Override
- protected void onPostExecute(List<Feed> result) {
- super.onPostExecute(result);
- boolean handleIntent = (feeds == null);
+ protected void onPostExecute(DBReader.NavDrawerData result) {
+ super.onPostExecute(navDrawerData);
+ boolean handleIntent = (navDrawerData == null);
- feeds = result;
+ navDrawerData = result;
navAdapter.notifyDataSetChanged();
if (handleIntent) {
diff --git a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
index 271cc19d5..e397ff2ca 100644
--- a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -61,6 +61,8 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
private Map<String, String> alternateFeedUrls;
private Downloader downloader;
+ private boolean isPaused;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
@@ -97,6 +99,18 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
}
@Override
+ protected void onResume() {
+ super.onResume();
+ isPaused = false;
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ isPaused = true;
+ }
+
+ @Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (feed != null && feed.getPreferences() != null) {
@@ -126,9 +140,11 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
if (status.isSuccessful()) {
parseFeed();
} else if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
- Dialog dialog = new FeedViewAuthenticationDialog(OnlineFeedViewActivity.this,
- R.string.authentication_notification_title, downloader.getDownloadRequest().getSource());
- dialog.show();
+ if (!isFinishing() && !isPaused) {
+ Dialog dialog = new FeedViewAuthenticationDialog(OnlineFeedViewActivity.this,
+ R.string.authentication_notification_title, downloader.getDownloadRequest().getSource());
+ dialog.show();
+ }
} else {
String errorMsg = status.getReason().getErrorString(
OnlineFeedViewActivity.this);
@@ -276,32 +292,30 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
}
private void showErrorDialog(String errorMsg) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.error_label);
- if (errorMsg != null) {
- builder.setMessage(getString(R.string.error_msg_prefix) + errorMsg);
- } else {
- builder.setMessage(R.string.error_msg_prefix);
- }
- builder.setNeutralButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
+ if (!isFinishing() && !isPaused) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.error_label);
+ if (errorMsg != null) {
+ builder.setMessage(getString(R.string.error_msg_prefix) + errorMsg);
+ } else {
+ builder.setMessage(R.string.error_msg_prefix);
+ }
+ builder.setNeutralButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
}
+ );
+ builder.setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ setResult(RESULT_ERROR);
+ finish();
}
- );
- builder.setOnCancelListener(new OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- setResult(RESULT_ERROR);
- finish();
- }
- });
-
- if (!isFinishing()) {
- builder.show();
+ });
}
}
diff --git a/src/de/danoeh/antennapod/activity/PreferenceActivity.java b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
index 1070c71f8..77ec579ed 100644
--- a/src/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -15,6 +15,7 @@ import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
+import android.support.v4.app.NavUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@@ -46,7 +47,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
private static final String PREF_FLATTR_THIS_APP = "prefFlattrThisApp";
private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
- private static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
+ private static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
private static final String PREF_OPML_EXPORT = "prefOpmlExport";
private static final String PREF_ABOUT = "prefAbout";
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
@@ -89,7 +90,8 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
return true;
}
- });
+ }
+ );
findPreference(PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@@ -101,7 +103,8 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
return true;
}
- });
+ }
+ );
findPreference(PREF_ABOUT).setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@@ -113,7 +116,8 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
return true;
}
- });
+ }
+ );
findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@@ -125,7 +129,8 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
return true;
}
- });
+ }
+ );
findPreference(PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@@ -135,10 +140,12 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
startActivityForResult(
new Intent(PreferenceActivity.this,
DirectoryChooserActivity.class),
- DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
+ DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED
+ );
return true;
}
- });
+ }
+ );
findPreference(UserPreferences.PREF_THEME)
.setOnPreferenceChangeListener(
new OnPreferenceChangeListener() {
@@ -153,18 +160,19 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
startActivity(i);
return true;
}
- });
+ }
+ );
findPreference(UserPreferences.PREF_ENABLE_AUTODL)
.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (newValue instanceof Boolean) {
- findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled((Boolean) newValue);
- setSelectedNetworksEnabled((Boolean) newValue && UserPreferences.isEnableAutodownloadWifiFilter());
- }
- return true;
- }
- });
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (newValue instanceof Boolean) {
+ findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled((Boolean) newValue);
+ setSelectedNetworksEnabled((Boolean) newValue && UserPreferences.isEnableAutodownloadWifiFilter());
+ }
+ return true;
+ }
+ });
findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
.setOnPreferenceChangeListener(
new OnPreferenceChangeListener() {
@@ -179,7 +187,8 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
return false;
}
}
- });
+ }
+ );
findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
.setOnPreferenceChangeListener(
new OnPreferenceChangeListener() {
@@ -190,7 +199,8 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
}
return true;
}
- });
+ }
+ );
findPreference(PREF_PLAYBACK_SPEED_LAUNCHER)
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
@@ -343,12 +353,14 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
+ Intent destIntent = new Intent(this, MainActivity.class);
+ destIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(destIntent);
finish();
- break;
+ return true;
default:
return false;
}
- return true;
}
@Override
@@ -389,7 +401,8 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
String key = preference.getKey();
ArrayList<String> prefValuesList = new ArrayList<String>(
Arrays.asList(UserPreferences
- .getAutodownloadSelectedNetworks()));
+ .getAutodownloadSelectedNetworks())
+ );
boolean newValue = ((CheckBoxPreference) preference)
.isChecked();
if (BuildConfig.DEBUG)
@@ -406,8 +419,9 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
UserPreferences.setAutodownloadSelectedNetworks(
PreferenceActivity.this, prefValuesList
- .toArray(new String[prefValuesList
- .size()]));
+ .toArray(new String[prefValuesList
+ .size()])
+ );
return true;
} else {
return false;
@@ -461,7 +475,17 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
.setBackgroundDrawable(
this.getWindow().getDecorView()
.getBackground().getConstantState()
- .newDrawable());
+ .newDrawable()
+ );
return false;
}
+
+ @Override
+ public void onBackPressed() {
+ // The default back button behavior has to be overwritten because changing the theme clears the back stack
+ Intent destIntent = new Intent(this, MainActivity.class);
+ destIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(destIntent);
+ finish();
+ }
}
diff --git a/src/de/danoeh/antennapod/adapter/AdapterUtils.java b/src/de/danoeh/antennapod/adapter/AdapterUtils.java
new file mode 100644
index 000000000..f393fb7d7
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/AdapterUtils.java
@@ -0,0 +1,57 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.res.Resources;
+import android.view.View;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.util.Converter;
+
+/**
+ * Utility methods for adapters
+ */
+public class AdapterUtils {
+
+ private AdapterUtils() {
+
+ }
+
+ /**
+ * Updates the contents of the TextView that shows the current playback position and the ProgressBar.
+ */
+ public static void updateEpisodePlaybackProgress(FeedItem item, Resources res, TextView txtvPos, ProgressBar episodeProgress) {
+ FeedMedia media = item.getMedia();
+ episodeProgress.setVisibility(View.GONE);
+ if (media == null) {
+ txtvPos.setVisibility(View.GONE);
+ return;
+ } else {
+ txtvPos.setVisibility(View.VISIBLE);
+ }
+
+ FeedItem.State state = item.getState();
+ if (state == FeedItem.State.PLAYING
+ || state == FeedItem.State.IN_PROGRESS) {
+ if (media.getDuration() > 0) {
+ episodeProgress.setVisibility(View.VISIBLE);
+ episodeProgress
+ .setProgress((int) (((double) media
+ .getPosition()) / media.getDuration() * 100));
+ txtvPos.setText(Converter
+ .getDurationStringLong(media.getDuration()
+ - media.getPosition()));
+ }
+ } else if (!media.isDownloaded()) {
+ txtvPos.setText(res.getString(
+ R.string.size_prefix)
+ + Converter.byteToString(media.getSize()));
+ } else {
+ txtvPos.setText(res.getString(
+ R.string.length_prefix)
+ + Converter.getDurationStringLong(media
+ .getDuration()));
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
index 5475f122f..c4a16d4db 100644
--- a/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -134,28 +134,8 @@ public class FeedItemlistAdapter extends BaseAdapter {
holder.lenSize.setVisibility(View.INVISIBLE);
} 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(context.getString(
- R.string.size_prefix)
- + Converter.byteToString(media.getSize()));
- } else {
- holder.lenSize.setText(context.getString(
- R.string.length_prefix)
- + Converter.getDurationStringLong(media
- .getDuration()));
- }
+ AdapterUtils.updateEpisodePlaybackProgress(item, context.getResources(), holder.lenSize, holder.episodeProgress);
- holder.lenSize.setVisibility(View.VISIBLE);
if (((ItemAccess) itemAccess).isInQueue(item)) {
holder.inPlaylist.setVisibility(View.VISIBLE);
} else {
@@ -166,9 +146,6 @@ public class FeedItemlistAdapter extends BaseAdapter {
item.getMedia())) {
holder.episodeProgress.setVisibility(View.VISIBLE);
holder.episodeProgress.setProgress(((ItemAccess) itemAccess).getItemDownloadProgressPercent(item));
- } else if (!(state == FeedItem.State.IN_PROGRESS
- || state == FeedItem.State.PLAYING)) {
- holder.episodeProgress.setVisibility(View.GONE);
}
TypedArray typeDrawables = context.obtainStyledAttributes(
diff --git a/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java b/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java
deleted file mode 100644
index 30c1ff880..000000000
--- a/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java
+++ /dev/null
@@ -1,174 +0,0 @@
-package de.danoeh.antennapod.adapter;
-
-import android.content.Context;
-import android.text.format.DateUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.ImageLoader;
-import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.storage.DownloadRequester;
-import de.danoeh.antennapod.storage.FeedItemStatistics;
-import de.danoeh.antennapod.util.ThemeUtils;
-
-public class FeedlistAdapter extends BaseAdapter {
- private static final String TAG = "FeedlistAdapter";
-
- private Context context;
- protected ItemAccess itemAccess;
-
- private int selectedItemIndex;
- private ImageLoader imageLoader;
- public static final int SELECTION_NONE = -1;
-
- public FeedlistAdapter(Context context, ItemAccess itemAccess) {
- super();
- if (context == null) {
- throw new IllegalArgumentException("context must not be null");
- }
- if (itemAccess == null) {
- throw new IllegalArgumentException("itemAccess must not be null");
- }
-
- this.context = context;
- this.itemAccess = itemAccess;
- selectedItemIndex = SELECTION_NONE;
- imageLoader = ImageLoader.getInstance();
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final Holder holder;
- final Feed feed = getItem(position);
- final FeedItemStatistics feedItemStatistics = itemAccess.getFeedItemStatistics(position);
-
- // Inflate Layout
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) context
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- convertView = inflater.inflate(R.layout.feedlist_item, null);
- holder.title = (TextView) convertView
- .findViewById(R.id.txtvFeedname);
-
- holder.newEpisodes = (TextView) convertView
- .findViewById(R.id.txtvNewEps);
- holder.inProgressEpisodes = (TextView) convertView
- .findViewById(R.id.txtvProgressEps);
- holder.newEpisodesLabel = (View) convertView
- .findViewById(R.id.lNewStatusLabel);
- holder.inProgressEpisodesLabel = (View) convertView
- .findViewById(R.id.lProgressStatusLabel);
- holder.image = (ImageView) convertView
- .findViewById(R.id.imgvFeedimage);
- holder.lastUpdate = (TextView) convertView
- .findViewById(R.id.txtvLastUpdate);
- holder.numberOfEpisodes = (TextView) convertView
- .findViewById(R.id.txtvNumEpisodes);
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
-
- }
-
- if (position == selectedItemIndex) {
- convertView.setBackgroundColor(convertView.getResources().getColor(
- ThemeUtils.getSelectionBackgroundColor()));
- } else {
- convertView.setBackgroundResource(0);
- }
-
- holder.title.setText(feed.getTitle());
-
- if (feedItemStatistics != null) {
- if (DownloadRequester.getInstance().isDownloadingFile(feed)) {
- holder.lastUpdate.setText(R.string.refreshing_label);
- } else {
- if (feedItemStatistics.lastUpdateKnown()) {
- holder.lastUpdate.setText(convertView.getResources().getString(
- R.string.most_recent_prefix)
- + DateUtils.getRelativeTimeSpanString(
- feedItemStatistics.getLastUpdate().getTime(),
- System.currentTimeMillis(), 0, 0));
- } else {
- holder.lastUpdate.setText("");
- }
- }
- holder.numberOfEpisodes.setText(feedItemStatistics.getNumberOfItems()
- + convertView.getResources()
- .getString(R.string.episodes_suffix));
-
- if (feedItemStatistics.getNumberOfNewItems() > 0) {
- holder.newEpisodes.setText(Integer.toString(feedItemStatistics.getNumberOfNewItems()));
- holder.newEpisodesLabel.setVisibility(View.VISIBLE);
- } else {
- holder.newEpisodesLabel.setVisibility(View.INVISIBLE);
- }
-
- if (feedItemStatistics.getNumberOfInProgressItems() > 0) {
- holder.inProgressEpisodes
- .setText(Integer.toString(feedItemStatistics.getNumberOfInProgressItems()));
- holder.inProgressEpisodesLabel.setVisibility(View.VISIBLE);
- } else {
- holder.inProgressEpisodesLabel.setVisibility(View.INVISIBLE);
- }
- }
- final String imageUrl = (feed.getImage() != null && feed.getImage().isDownloaded()) ? feed.getImage()
- .getFile_url() : null;
- imageLoader.loadThumbnailBitmap(
- feed.getImage(),
- holder.image,
- (int) convertView.getResources().getDimension(
- R.dimen.thumbnail_length));
-
- return convertView;
- }
-
- static class Holder {
- TextView title;
- TextView lastUpdate;
- TextView numberOfEpisodes;
- TextView newEpisodes;
- TextView inProgressEpisodes;
- ImageView image;
- View newEpisodesLabel;
- View inProgressEpisodesLabel;
- }
-
- public int getSelectedItemIndex() {
- return selectedItemIndex;
- }
-
- public void setSelectedItemIndex(int selectedItemIndex) {
- this.selectedItemIndex = selectedItemIndex;
- notifyDataSetChanged();
- }
-
- @Override
- public int getCount() {
- return itemAccess.getCount();
- }
-
- @Override
- public Feed getItem(int position) {
- return itemAccess.getItem(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- public interface ItemAccess {
- int getCount();
-
- Feed getItem(int position);
-
- FeedItemStatistics getFeedItemStatistics(int position);
- }
-}
diff --git a/src/de/danoeh/antennapod/adapter/NavListAdapter.java b/src/de/danoeh/antennapod/adapter/NavListAdapter.java
index 928ec5dde..536bf80e3 100644
--- a/src/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -36,9 +36,9 @@ public class NavListAdapter extends BaseAdapter {
this.itemAccess = itemAccess;
this.context = context;
- TypedArray ta = context.obtainStyledAttributes(new int[] {R.attr.ic_new, R.attr.stat_playlist,
+ TypedArray ta = context.obtainStyledAttributes(new int[]{R.attr.ic_new, R.attr.stat_playlist,
R.attr.av_download, R.attr.device_access_time, R.attr.content_new});
- drawables = new Drawable[] {ta.getDrawable(0), ta.getDrawable(1), ta.getDrawable(2),
+ drawables = new Drawable[]{ta.getDrawable(0), ta.getDrawable(1), ta.getDrawable(2),
ta.getDrawable(3), ta.getDrawable(4)};
ta.recycle();
}
@@ -113,6 +113,7 @@ public class NavListAdapter extends BaseAdapter {
convertView = inflater.inflate(R.layout.nav_listitem, null);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.count = (TextView) convertView.findViewById(R.id.txtvCount);
holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
convertView.setTag(holder);
} else {
@@ -120,6 +121,27 @@ public class NavListAdapter extends BaseAdapter {
}
holder.title.setText(title);
+
+ if (NAV_TITLES[position] == R.string.queue_label) {
+ int queueSize = itemAccess.getQueueSize();
+ if (queueSize > 0) {
+ holder.count.setVisibility(View.VISIBLE);
+ holder.count.setText(String.valueOf(queueSize));
+ } else {
+ holder.count.setVisibility(View.GONE);
+ }
+ } else if (NAV_TITLES[position] == R.string.all_episodes_label) {
+ int unreadItems = itemAccess.getNumberOfUnreadItems();
+ if (unreadItems > 0) {
+ holder.count.setVisibility(View.VISIBLE);
+ holder.count.setText(String.valueOf(unreadItems));
+ } else {
+ holder.count.setVisibility(View.GONE);
+ }
+ } else {
+ holder.count.setVisibility(View.GONE);
+ }
+
holder.image.setImageDrawable(drawables[position]);
return convertView;
@@ -174,6 +196,7 @@ public class NavListAdapter extends BaseAdapter {
static class NavHolder {
TextView title;
+ TextView count;
ImageView image;
}
@@ -193,6 +216,10 @@ public class NavListAdapter extends BaseAdapter {
public Feed getItem(int position);
public int getSelectedItemIndex();
+
+ public int getQueueSize();
+
+ public int getNumberOfUnreadItems();
}
}
diff --git a/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
index 4a959dfd2..555a334f6 100644
--- a/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
@@ -66,6 +66,7 @@ public class NewEpisodesListAdapter extends BaseAdapter {
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
holder.pubDate = (TextView) convertView
.findViewById(R.id.txtvPublished);
+ holder.statusUnread = convertView.findViewById(R.id.statusUnread);
holder.butSecondary = (ImageButton) convertView
.findViewById(R.id.butSecondaryAction);
holder.queueStatus = (ImageView) convertView
@@ -81,6 +82,11 @@ public class NewEpisodesListAdapter extends BaseAdapter {
holder.title.setText(item.getTitle());
holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE));
+ if (item.isRead()) {
+ holder.statusUnread.setVisibility(View.GONE);
+ } else {
+ holder.statusUnread.setVisibility(View.VISIBLE);
+ }
FeedMedia media = item.getMedia();
if (media != null) {
@@ -140,6 +146,7 @@ public class NewEpisodesListAdapter extends BaseAdapter {
static class Holder {
TextView title;
TextView pubDate;
+ View statusUnread;
ImageView queueStatus;
ImageView imageView;
ProgressBar downloadProgress;
diff --git a/src/de/danoeh/antennapod/adapter/QueueListAdapter.java b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
index fb6848a1e..ecce1b473 100644
--- a/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
@@ -61,7 +61,8 @@ public class QueueListAdapter extends BaseAdapter {
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
holder.butSecondary = (ImageButton) convertView
.findViewById(R.id.butSecondaryAction);
- holder.downloadProgress = (ProgressBar) convertView
+ holder.position = (TextView) convertView.findViewById(R.id.txtvPosition);
+ holder.progress = (ProgressBar) convertView
.findViewById(R.id.pbar_download_progress);
holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
convertView.setTag(holder);
@@ -71,20 +72,17 @@ public class QueueListAdapter extends BaseAdapter {
holder.title.setText(item.getTitle());
+ AdapterUtils.updateEpisodePlaybackProgress(item, context.getResources(), holder.position, holder.progress);
+
FeedMedia media = item.getMedia();
if (media != null) {
final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
-
- if (isDownloadingMedia) {
- holder.downloadProgress.setVisibility(View.VISIBLE);
- } else {
- holder.downloadProgress.setVisibility(View.GONE);
- }
if (!media.isDownloaded()) {
if (isDownloadingMedia) {
// item is being downloaded
- holder.downloadProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
+ holder.progress.setVisibility(View.VISIBLE);
+ holder.progress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
}
}
}
@@ -116,7 +114,8 @@ public class QueueListAdapter extends BaseAdapter {
static class Holder {
TextView title;
ImageView imageView;
- ProgressBar downloadProgress;
+ TextView position;
+ ProgressBar progress;
ImageButton butSecondary;
}
diff --git a/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java b/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java
index b90d78c14..1d069daa5 100644
--- a/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java
+++ b/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java
@@ -189,6 +189,10 @@ public class ImageDiskCache {
* The image will be stored in the thumbnail cache.
*/
public void loadThumbnailBitmap(final String url, final ImageView target, final int length) {
+ if (url == null) {
+ Log.w(TAG, "loadThumbnailBitmap: Call was ignored because url = null");
+ return;
+ }
final ImageLoader il = ImageLoader.getInstance();
target.setTag(R.id.image_disk_cache_key, url);
if (diskCache != null) {
@@ -217,6 +221,10 @@ public class ImageDiskCache {
* The image will be stored in the cover cache.
*/
public void loadCoverBitmap(final String url, final ImageView target, final int length) {
+ if (url == null) {
+ Log.w(TAG, "loadCoverBitmap: Call was ignored because url = null");
+ return;
+ }
final ImageLoader il = ImageLoader.getInstance();
target.setTag(R.id.image_disk_cache_key, url);
if (diskCache != null) {
diff --git a/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
index 0c42bdd65..a0861779c 100644
--- a/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -7,7 +7,6 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
-import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.view.*;
@@ -55,7 +54,6 @@ public class NewEpisodesFragment extends Fragment {
private DragSortListView listView;
- private SwipeRefreshLayout swipeRefreshLayout;
private NewEpisodesListAdapter listAdapter;
private TextView txtvEmpty;
private ProgressBar progLoading;
@@ -202,7 +200,6 @@ public class NewEpisodesFragment extends Fragment {
View root = inflater.inflate(R.layout.new_episodes_fragment, container, false);
- swipeRefreshLayout = (SwipeRefreshLayout) root.findViewById(R.id.swipeRefreshLayout);
listView = (DragSortListView) root.findViewById(android.R.id.list);
txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
@@ -220,16 +217,6 @@ public class NewEpisodesFragment extends Fragment {
});
final int secondColor = (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) ? R.color.swipe_refresh_secondary_color_dark : R.color.swipe_refresh_secondary_color_light;
- swipeRefreshLayout.setColorScheme(R.color.bright_blue, secondColor, R.color.bright_blue, secondColor);
- swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
- @Override
- public void onRefresh() {
- List<Feed> feeds = ((MainActivity) getActivity()).getFeeds();
- if (feeds != null) {
- DBTasks.refreshAllFeeds(getActivity(), feeds);
- }
- }
- });
if (!itemsLoaded) {
progLoading.setVisibility(View.VISIBLE);
@@ -331,18 +318,9 @@ public class NewEpisodesFragment extends Fragment {
if (!viewsCreated) {
return;
}
-
- if (DownloadService.isRunning
- && DownloadRequester.getInstance().isDownloadingFeeds()) {
- swipeRefreshLayout.setRefreshing(true);
-
- } else {
- swipeRefreshLayout.setRefreshing(false);
-
- // if case other fragments have set this to true, this fragment should remove the progress indicator
- ((ActionBarActivity) getActivity())
- .setSupportProgressBarIndeterminateVisibility(false);
- }
+ ((ActionBarActivity) getActivity())
+ .setSupportProgressBarIndeterminateVisibility(DownloadService.isRunning
+ && DownloadRequester.getInstance().isDownloadingFeeds());
}
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java
index ed2f5d532..4f60ef8d6 100644
--- a/src/de/danoeh/antennapod/service/download/DownloadService.java
+++ b/src/de/danoeh/antennapod/service/download/DownloadService.java
@@ -890,6 +890,7 @@ public class DownloadService extends Service {
if (successful) {
return savedFeed;
} else {
+ numberOfDownloads.decrementAndGet();
saveDownloadStatus(new DownloadStatus(savedFeed,
savedFeed.getHumanReadableIdentifier(), reason, successful,
reasonDetailed));
diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java
index fb2569bfd..b7ff62129 100644
--- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java
+++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java
@@ -541,6 +541,7 @@ public class PlaybackService extends Service {
(nextMedia.getMediaType() == MediaType.VIDEO) ? EXTRA_CODE_VIDEO : EXTRA_CODE_AUDIO);
} else {
sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0);
+ mediaPlayer.stop();
//stopSelf();
}
}
diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java b/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java
index 24ff9b3fa..2915da5a1 100644
--- a/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java
+++ b/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java
@@ -77,7 +77,8 @@ public class PlaybackServiceMediaPlayer {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (BuildConfig.DEBUG) Log.d(TAG, "Rejected execution of runnable");
}
- });
+ }
+ );
mediaPlayer = null;
statusBeforeSeeking = null;
@@ -150,6 +151,8 @@ public class PlaybackServiceMediaPlayer {
if (media != null) {
if (!forceReset && media.getIdentifier().equals(playable.getIdentifier())) {
// episode is already playing -> ignore method call
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Method call to playMediaObject was ignored: media file already playing.");
return;
} else {
// stop playback of this episode
@@ -284,7 +287,8 @@ public class PlaybackServiceMediaPlayer {
reinit();
}
} else {
- if (BuildConfig.DEBUG) Log.d(TAG, "Ignoring call to pause: Player is in " + playerStatus + " state");
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Ignoring call to pause: Player is in " + playerStatus + " state");
}
playerLock.unlock();
@@ -385,9 +389,10 @@ public class PlaybackServiceMediaPlayer {
/**
* Seeks to the specified position. If the PSMP object is in an invalid state, this method will do nothing.
+ *
* @param t The position to seek to in milliseconds. t < 0 will be interpreted as t = 0
- * <p/>
- * This method is executed on the caller's thread.
+ * <p/>
+ * This method is executed on the caller's thread.
*/
private void seekToSync(int t) {
if (t < 0) {
@@ -758,6 +763,29 @@ public class PlaybackServiceMediaPlayer {
}
/**
+ * Moves the PlaybackServiceMediaPlayer into STOPPED state. This call is only valid if the player is currently in
+ * INDETERMINATE state, for example after a call to endPlayback.
+ * This method will only take care of changing the PlayerStatus of this object! Other tasks like
+ * abandoning audio focus have to be done with other methods.
+ */
+ public void stop() {
+ executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ playerLock.lock();
+
+ if (playerStatus == PlayerStatus.INDETERMINATE) {
+ setPlayerStatus(PlayerStatus.STOPPED, null);
+ } else {
+ if (BuildConfig.DEBUG) Log.d(TAG, "Ignored call to stop: Current player state is: " + playerStatus);
+ }
+ playerLock.unlock();
+
+ }
+ });
+ }
+
+ /**
* Holds information about a PSMP object.
*/
public class PSMPInfo {
diff --git a/src/de/danoeh/antennapod/storage/DBReader.java b/src/de/danoeh/antennapod/storage/DBReader.java
index 4aeca7cd6..e49ea4f83 100644
--- a/src/de/danoeh/antennapod/storage/DBReader.java
+++ b/src/de/danoeh/antennapod/storage/DBReader.java
@@ -56,6 +56,14 @@ public final class DBReader {
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
+ List<Feed> result = getFeedList(adapter);
+ adapter.close();
+ return result;
+ }
+
+ private static List<Feed> getFeedList(PodDBAdapter adapter) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Extracting Feedlist");
Cursor feedlistCursor = adapter.getAllFeedsCursor();
List<Feed> feeds = new ArrayList<Feed>(feedlistCursor.getCount());
@@ -509,8 +517,8 @@ public final class DBReader {
* Loads a list of FeedItems sorted by pubDate in descending order.
*
* @param context A context that is used for opening a database connection.
- * @param limit The maximum number of episodes that should be loaded.
- * */
+ * @param limit The maximum number of episodes that should be loaded.
+ */
public static List<FeedItem> getRecentlyPublishedEpisodes(Context context, int limit) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Extracting recently published items list");
@@ -596,7 +604,8 @@ public final class DBReader {
.getString(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE_INDEX);
Date completionDate = new Date(
logCursor
- .getLong(PodDBAdapter.KEY_COMPLETION_DATE_INDEX));
+ .getLong(PodDBAdapter.KEY_COMPLETION_DATE_INDEX)
+ );
downloadLog.add(new DownloadStatus(id, title, feedfileId,
feedfileType, successful, DownloadError.fromCode(reason), completionDate,
reasonDetailed));
@@ -787,7 +796,8 @@ public final class DBReader {
cursor.getString(cursor
.getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL)),
cursor.getInt(cursor
- .getColumnIndex(PodDBAdapter.KEY_DOWNLOADED)) > 0);
+ .getColumnIndex(PodDBAdapter.KEY_DOWNLOADED)) > 0
+ );
cursor.close();
return image;
}
@@ -865,4 +875,34 @@ public final class DBReader {
adapter.close();
return empty;
}
+
+ /**
+ * Returns data necessary for displaying the navigation drawer. This includes
+ * the list of subscriptions, the number of items in the queue and the number of unread
+ * items.
+ *
+ * @param context A context that is used for opening a database connection.
+ */
+ public static NavDrawerData getNavDrawerData(Context context) {
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ List<Feed> feeds = getFeedList(adapter);
+ int queueSize = adapter.getQueueSize();
+ int numUnreadItems = adapter.getNumberOfUnreadItems();
+ NavDrawerData result = new NavDrawerData(feeds, queueSize, numUnreadItems);
+ adapter.close();
+ return result;
+ }
+
+ public static class NavDrawerData {
+ public List<Feed> feeds;
+ public int queueSize;
+ public int numUnreadItems;
+
+ public NavDrawerData(List<Feed> feeds, int queueSize, int numUnreadItems) {
+ this.feeds = feeds;
+ this.queueSize = queueSize;
+ this.numUnreadItems = numUnreadItems;
+ }
+ }
}
diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
index 285709537..06c8b1fc9 100644
--- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java
+++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.storage;
-import android.app.backup.BackupManager;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -1107,6 +1106,17 @@ public class PodDBAdapter {
}
+ public int getQueueSize() {
+ final String query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_QUEUE);
+ Cursor c = db.rawQuery(query, null);
+ int result = 0;
+ if (c.moveToFirst()) {
+ result = c.getInt(0);
+ }
+ c.close();
+ return result;
+ }
+
public final int getNumberOfUnreadItems() {
final String query = "SELECT COUNT(DISTINCT " + KEY_ID + ") AS count FROM " + TABLE_NAME_FEED_ITEMS +
" WHERE " + KEY_READ + " = 0";
diff --git a/src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java b/src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java
index f4726504e..6e44c8a0f 100644
--- a/src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java
+++ b/src/instrumentationTest/de/test/antennapod/service/download/HttpDownloaderTest.java
@@ -22,7 +22,6 @@ public class HttpDownloaderTest extends InstrumentationTestCase {
private File destDir;
private HTTPBin httpServer;
- private static final String BASE_URL = "http://127.0.0.1:" + HTTPBin.PORT;
public HttpDownloaderTest() {
super();
@@ -79,15 +78,15 @@ public class HttpDownloaderTest extends InstrumentationTestCase {
}
- private static final String URL_404 = BASE_URL + "/status/404";
- private static final String URL_AUTH = BASE_URL + "/basic-auth/user/passwd";
+ private static final String URL_404 = HTTPBin.BASE_URL + "/status/404";
+ private static final String URL_AUTH = HTTPBin.BASE_URL + "/basic-auth/user/passwd";
public void testPassingHttp() {
- download(BASE_URL + "/status/200", "test200", true);
+ download(HTTPBin.BASE_URL + "/status/200", "test200", true);
}
public void testRedirect() {
- download(BASE_URL + "/redirect/4", "testRedirect", true);
+ download(HTTPBin.BASE_URL + "/redirect/4", "testRedirect", true);
}
public void testGzip() {
@@ -99,7 +98,7 @@ public class HttpDownloaderTest extends InstrumentationTestCase {
}
public void testCancel() {
- final String url = BASE_URL + "/delay/3";
+ final String url = HTTPBin.BASE_URL + "/delay/3";
FeedFileImpl feedFile = setupFeedFile(url, "delay", true);
final Downloader downloader = new HttpDownloader(new DownloadRequest(feedFile.getFile_url(), url, "delay", 0, feedFile.getTypeAsInt()));
Thread t = new Thread() {
diff --git a/src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java b/src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java
index cb854b88d..c42c7a0cc 100644
--- a/src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java
+++ b/src/instrumentationTest/de/test/antennapod/storage/DBReaderTest.java
@@ -365,4 +365,44 @@ public class DBReaderTest extends InstrumentationTestCase {
assertEquals("Wrong entry at index " + i, feeds.get(i).getId(), statistics.get(i).getFeedID());
}
}
+
+ public void testGetNavDrawerDataQueueEmptyNoUnreadItems() {
+ final Context context = getInstrumentation().getTargetContext();
+ final int NUM_FEEDS = 10;
+ final int NUM_ITEMS = 10;
+ List<Feed> feeds = DBTestUtils.saveFeedlist(context, NUM_FEEDS, NUM_ITEMS, true);
+ DBReader.NavDrawerData navDrawerData = DBReader.getNavDrawerData(context);
+ assertEquals(NUM_FEEDS, navDrawerData.feeds.size());
+ assertEquals(0, navDrawerData.numUnreadItems);
+ assertEquals(0, navDrawerData.queueSize);
+ }
+
+ public void testGetNavDrawerDataQueueNotEmptyWithUnreadItems() {
+ final Context context = getInstrumentation().getTargetContext();
+ final int NUM_FEEDS = 10;
+ final int NUM_ITEMS = 10;
+ final int NUM_QUEUE = 1;
+ final int NUM_UNREAD = 2;
+ List<Feed> feeds = DBTestUtils.saveFeedlist(context, NUM_FEEDS, NUM_ITEMS, true);
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ for (int i = 0; i < NUM_UNREAD; i++) {
+ FeedItem item = feeds.get(0).getItems().get(i);
+ item.setRead(false);
+ adapter.setSingleFeedItem(item);
+ }
+ List<FeedItem> queue = new ArrayList<FeedItem>();
+ for (int i = 0; i < NUM_QUEUE; i++) {
+ FeedItem item = feeds.get(1).getItems().get(i);
+ queue.add(item);
+ }
+ adapter.setQueue(queue);
+
+ adapter.close();
+
+ DBReader.NavDrawerData navDrawerData = DBReader.getNavDrawerData(context);
+ assertEquals(NUM_FEEDS, navDrawerData.feeds.size());
+ assertEquals(NUM_UNREAD, navDrawerData.numUnreadItems);
+ assertEquals(NUM_QUEUE, navDrawerData.queueSize);
+ }
}
diff --git a/src/instrumentationTest/de/test/antennapod/ui/MainActivityTest.java b/src/instrumentationTest/de/test/antennapod/ui/MainActivityTest.java
new file mode 100644
index 000000000..2dfd6a544
--- /dev/null
+++ b/src/instrumentationTest/de/test/antennapod/ui/MainActivityTest.java
@@ -0,0 +1,118 @@
+package instrumentationTest.de.test.antennapod.ui;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.View;
+import com.robotium.solo.Solo;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.feed.EventDistributor;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.storage.PodDBAdapter;
+
+/**
+ * User interface tests for MainActivity
+ */
+public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private Solo solo;
+ private UITestUtils uiTestUtils;
+
+ public MainActivityTest() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ solo = new Solo(getInstrumentation(), getActivity());
+ uiTestUtils = new UITestUtils(getInstrumentation().getTargetContext());
+ uiTestUtils.setup();
+ // create database
+ PodDBAdapter adapter = new PodDBAdapter(getInstrumentation().getTargetContext());
+ adapter.open();
+ adapter.close();
+
+ // override first launch preference
+ SharedPreferences prefs = getInstrumentation().getTargetContext().getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
+ prefs.edit().putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false).commit();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ uiTestUtils.tearDown();
+ solo.finishOpenedActivities();
+ PodDBAdapter.deleteDatabase(getInstrumentation().getTargetContext());
+ super.tearDown();
+ }
+
+ public void testAddFeed() throws Exception {
+ uiTestUtils.addHostedFeedData();
+ final Feed feed = uiTestUtils.hostedFeeds.get(0);
+ solo.setNavigationDrawer(Solo.OPENED);
+ solo.clickOnText(solo.getString(R.string.add_feed_label));
+ solo.enterText(0, feed.getDownload_url());
+ solo.clickOnButton(0);
+ solo.waitForActivity(DefaultOnlineFeedViewActivity.class);
+ solo.waitForView(R.id.butSubscribe);
+ assertEquals(solo.getString(R.string.subscribe_label), solo.getButton(0).getText().toString());
+ solo.clickOnButton(0);
+ solo.waitForText(solo.getString(R.string.subscribed_label));
+ }
+
+ public void testClickNavDrawer() throws Exception {
+ uiTestUtils.addLocalFeedData(false);
+
+ final View home = solo.getView(android.R.id.home);
+
+ // all episodes
+ solo.waitForView(android.R.id.list);
+ assertEquals(solo.getString(R.string.all_episodes_label), getActionbarTitle());
+ // queue
+ solo.clickOnView(home);
+ solo.clickOnText(solo.getString(R.string.queue_label));
+ solo.waitForView(android.R.id.list);
+ assertEquals(solo.getString(R.string.queue_label), getActionbarTitle());
+
+ // downloads
+ solo.clickOnView(home);
+ solo.clickOnText(solo.getString(R.string.downloads_label));
+ solo.waitForView(android.R.id.list);
+ assertEquals(solo.getString(R.string.downloads_label), getActionbarTitle());
+
+ // playback history
+ solo.clickOnView(home);
+ solo.clickOnText(solo.getString(R.string.playback_history_label));
+ solo.waitForView(android.R.id.list);
+ assertEquals(solo.getString(R.string.playback_history_label), getActionbarTitle());
+
+ // add podcast
+ solo.clickOnView(home);
+ solo.clickOnText(solo.getString(R.string.add_feed_label));
+ solo.waitForView(R.id.txtvFeedurl);
+ assertEquals(solo.getString(R.string.add_feed_label), getActionbarTitle());
+
+ // podcasts
+ for (int i = 0; i < uiTestUtils.hostedFeeds.size(); i++) {
+ Feed f = uiTestUtils.hostedFeeds.get(i);
+ solo.clickOnView(home);
+ solo.clickOnText(f.getTitle());
+ solo.waitForView(android.R.id.list);
+ assertEquals("", getActionbarTitle());
+ }
+ }
+
+ private String getActionbarTitle() {
+ return ((MainActivity)solo.getCurrentActivity()).getMainActivtyActionBar().getTitle().toString();
+ }
+
+ public void testGoToPreferences() {
+ solo.setNavigationDrawer(Solo.CLOSED);
+ solo.clickOnMenuItem(solo.getString(R.string.settings_label));
+ solo.waitForActivity(PreferenceActivity.class);
+ }
+}
diff --git a/src/instrumentationTest/de/test/antennapod/ui/PlaybackTest.java b/src/instrumentationTest/de/test/antennapod/ui/PlaybackTest.java
new file mode 100644
index 000000000..835973560
--- /dev/null
+++ b/src/instrumentationTest/de/test/antennapod/ui/PlaybackTest.java
@@ -0,0 +1,149 @@
+package instrumentationTest.de.test.antennapod.ui;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.test.ActivityInstrumentationTestCase2;
+import android.widget.TextView;
+import com.robotium.solo.Solo;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.AudioplayerActivity;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.preferences.UserPreferences;
+import de.danoeh.antennapod.service.playback.PlaybackService;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.storage.PodDBAdapter;
+
+import java.util.List;
+
+/**
+ * Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity
+ */
+public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private Solo solo;
+ private UITestUtils uiTestUtils;
+
+ public PlaybackTest() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ solo = new Solo(getInstrumentation(), getActivity());
+ uiTestUtils = new UITestUtils(getInstrumentation().getTargetContext());
+ uiTestUtils.setup();
+ // create database
+ PodDBAdapter adapter = new PodDBAdapter(getInstrumentation().getTargetContext());
+ adapter.open();
+ adapter.close();
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getInstrumentation().getTargetContext());
+ prefs.edit().putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false).commit();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ uiTestUtils.tearDown();
+ solo.finishOpenedActivities();
+ PodDBAdapter.deleteDatabase(getInstrumentation().getTargetContext());
+
+ // shut down playback service
+ skipEpisode();
+ getInstrumentation().getTargetContext().sendBroadcast(
+ new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
+
+ super.tearDown();
+ }
+
+ private void setContinuousPlaybackPreference(boolean value) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getInstrumentation().getTargetContext());
+ prefs.edit().putBoolean(UserPreferences.PREF_FOLLOW_QUEUE, value).commit();
+ }
+
+ private void skipEpisode() {
+ Intent skipIntent = new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE);
+ getInstrumentation().getTargetContext().sendBroadcast(skipIntent);
+ }
+
+ private void startLocalPlayback() {
+ assertTrue(solo.waitForActivity(MainActivity.class));
+ solo.setNavigationDrawer(Solo.CLOSED);
+ solo.clickOnView(solo.getView(R.id.butSecondaryAction));
+ assertTrue(solo.waitForActivity(AudioplayerActivity.class));
+ assertTrue(solo.waitForView(solo.getView(R.id.butPlay)));
+ }
+
+ private void startLocalPlaybackFromQueue() {
+ assertTrue(solo.waitForActivity(MainActivity.class));
+ solo.clickOnView(solo.getView(android.R.id.home));
+ solo.clickOnText(solo.getString(R.string.queue_label));
+ assertTrue(solo.waitForView(solo.getView(R.id.butSecondaryAction)));
+ solo.clickOnImageButton(0);
+ assertTrue(solo.waitForActivity(AudioplayerActivity.class));
+ assertTrue(solo.waitForView(solo.getView(R.id.butPlay)));
+ }
+
+ public void testStartLocal() throws Exception {
+ uiTestUtils.addLocalFeedData(true);
+ DBWriter.clearQueue(getInstrumentation().getTargetContext()).get();
+ startLocalPlayback();
+
+ solo.clickOnView(solo.getView(R.id.butPlay));
+ }
+
+ public void testContinousPlaybackOffSingleEpisode() throws Exception {
+ setContinuousPlaybackPreference(false);
+ uiTestUtils.addLocalFeedData(true);
+ DBWriter.clearQueue(getInstrumentation().getTargetContext()).get();
+ startLocalPlayback();
+ assertTrue(solo.waitForActivity(MainActivity.class));
+ }
+
+
+ public void testContinousPlaybackOffMultipleEpisodes() throws Exception {
+ setContinuousPlaybackPreference(false);
+ uiTestUtils.addLocalFeedData(true);
+ List<FeedItem> queue = DBReader.getQueue(getInstrumentation().getTargetContext());
+ FeedItem second = queue.get(1);
+
+ startLocalPlaybackFromQueue();
+ assertTrue(solo.waitForText(second.getTitle()));
+ }
+
+ public void testContinuousPlaybackOnMultipleEpisodes() throws Exception {
+ setContinuousPlaybackPreference(true);
+ uiTestUtils.addLocalFeedData(true);
+ List<FeedItem> queue = DBReader.getQueue(getInstrumentation().getTargetContext());
+ FeedItem second = queue.get(1);
+
+ startLocalPlaybackFromQueue();
+ assertTrue(solo.waitForText(second.getTitle()));
+ }
+
+ /**
+ * Check if an episode can be played twice without problems.
+ */
+ private void replayEpisodeCheck(boolean followQueue) throws Exception {
+ setContinuousPlaybackPreference(followQueue);
+ uiTestUtils.addLocalFeedData(true);
+ DBWriter.clearQueue(getInstrumentation().getTargetContext()).get();
+ String title = ((TextView) solo.getView(R.id.txtvTitle)).getText().toString();
+ startLocalPlayback();
+ assertTrue(solo.waitForText(title));
+ assertTrue(solo.waitForActivity(MainActivity.class));
+ startLocalPlayback();
+ assertTrue(solo.waitForText(title));
+ assertTrue(solo.waitForActivity(MainActivity.class));
+ }
+
+ public void testReplayEpisodeContinuousPlaybackOn() throws Exception {
+ replayEpisodeCheck(true);
+ }
+
+ public void testReplayEpisodeContinuousPlaybackOff() throws Exception {
+ replayEpisodeCheck(false);
+ }
+}
diff --git a/src/instrumentationTest/de/test/antennapod/ui/UITestUtils.java b/src/instrumentationTest/de/test/antennapod/ui/UITestUtils.java
new file mode 100644
index 000000000..a02d4e55c
--- /dev/null
+++ b/src/instrumentationTest/de/test/antennapod/ui/UITestUtils.java
@@ -0,0 +1,194 @@
+package instrumentationTest.de.test.antennapod.ui;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import de.danoeh.antennapod.feed.*;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.storage.PodDBAdapter;
+import instrumentationTest.de.test.antennapod.util.service.download.HTTPBin;
+import instrumentationTest.de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
+import junit.framework.Assert;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Utility methods for UI tests.
+ * Starts a web server that hosts feeds, episodes and images.
+ */
+public class UITestUtils {
+
+ private static final String DATA_FOLDER = "test/UITestUtils";
+
+ public static final int NUM_FEEDS = 5;
+ public static final int NUM_ITEMS_PER_FEED = 10;
+
+
+ private Context context;
+ private HTTPBin server = new HTTPBin();
+ private File destDir;
+ private File hostedFeedDir;
+ private File hostedMediaDir;
+
+ public List<Feed> hostedFeeds = new ArrayList<Feed>();
+
+ public UITestUtils(Context context) {
+ this.context = context;
+ }
+
+
+ public void setup() throws IOException {
+ destDir = context.getExternalFilesDir(DATA_FOLDER);
+ destDir.mkdir();
+ hostedFeedDir = new File(destDir, "hostedFeeds");
+ hostedFeedDir.mkdir();
+ hostedMediaDir = new File(destDir, "hostedMediaDir");
+ hostedMediaDir.mkdir();
+ Assert.assertTrue(destDir.exists());
+ Assert.assertTrue(hostedFeedDir.exists());
+ Assert.assertTrue(hostedMediaDir.exists());
+ server.start();
+ }
+
+ public void tearDown() throws IOException {
+ FileUtils.deleteDirectory(destDir);
+ FileUtils.deleteDirectory(hostedMediaDir);
+ FileUtils.deleteDirectory(hostedFeedDir);
+ server.stop();
+
+ if (localFeedDataAdded) {
+ PodDBAdapter.deleteDatabase(context);
+ }
+ }
+
+ private String hostFeed(Feed feed) throws IOException {
+ File feedFile = new File(hostedFeedDir, feed.getTitle());
+ FileOutputStream out = new FileOutputStream(feedFile);
+ RSS2Generator generator = new RSS2Generator();
+ generator.writeFeed(feed, out, "UTF-8", 0);
+ out.close();
+ int id = server.serveFile(feedFile);
+ Assert.assertTrue(id != -1);
+ return String.format("%s/files/%d", HTTPBin.BASE_URL, id);
+ }
+
+ private String hostFile(File file) {
+ int id = server.serveFile(file);
+ Assert.assertTrue(id != -1);
+ return String.format("%s/files/%d", HTTPBin.BASE_URL, id);
+ }
+
+ private File newBitmapFile(String name) throws IOException {
+ File imgFile = new File(destDir, name);
+ Bitmap bitmap = Bitmap.createBitmap(128, 128, Bitmap.Config.ARGB_8888);
+ FileOutputStream out = new FileOutputStream(imgFile);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 1, out);
+ out.close();
+ return imgFile;
+ }
+
+ private File newMediaFile(String name) throws IOException {
+ File mediaFile = new File(hostedMediaDir, name);
+ Assert.assertFalse(mediaFile.exists());
+
+ InputStream in = context.getAssets().open("testfile.mp3");
+ Assert.assertNotNull(in);
+
+ FileOutputStream out = new FileOutputStream(mediaFile);
+ IOUtils.copy(in, out);
+ out.close();
+
+ return mediaFile;
+ }
+
+ private boolean feedDataHosted = false;
+
+ /**
+ * Adds feeds, images and episodes to the webserver for testing purposes.
+ */
+ public void addHostedFeedData() throws IOException {
+ if (feedDataHosted) throw new IllegalStateException("addHostedFeedData was called twice on the same instance");
+ for (int i = 0; i < NUM_FEEDS; i++) {
+ File bitmapFile = newBitmapFile("image" + i);
+ FeedImage image = new FeedImage(0, "image " + i, null, hostFile(bitmapFile), false);
+ Feed feed = new Feed(0, new Date(), "Title " + i, "http://example.com/" + i, "Description of feed " + i,
+ "http://example.com/pay/feed" + i, "author " + i, "en", Feed.TYPE_RSS2, "feed" + i, image, null,
+ "http://example.com/feed/src/" + i, false);
+ image.setOwner(feed);
+
+ // create items
+ List<FeedItem> items = new ArrayList<FeedItem>();
+ for (int j = 0; j < NUM_ITEMS_PER_FEED; j++) {
+ FeedItem item = new FeedItem(0, "item" + j, "item" + j, "http://example.com/feed" + i + "/item/" + j, new Date(), true, feed);
+ items.add(item);
+
+ File mediaFile = newMediaFile("feed-" + i + "-episode-" + j + ".mp3");
+ item.setMedia(new FeedMedia(0, item, 0, 0, mediaFile.length(), "audio/mp3", null, hostFile(mediaFile), false, null, 0));
+
+ }
+ feed.setItems(items);
+ feed.setDownload_url(hostFeed(feed));
+ hostedFeeds.add(feed);
+ }
+ feedDataHosted = true;
+ }
+
+
+ private boolean localFeedDataAdded = false;
+
+ /**
+ * Adds feeds, images and episodes to the local database. This method will also call addHostedFeedData if it has not
+ * been called yet.
+ *
+ * Adds one item of each feed to the queue and to the playback history.
+ *
+ * This method should NOT be called if the testing class wants to download the hosted feed data.
+ *
+ * @param downloadEpisodes true if episodes should also be marked as downloaded.
+ */
+ public void addLocalFeedData(boolean downloadEpisodes) throws Exception {
+ if (localFeedDataAdded) throw new IllegalStateException("addLocalFeedData was called twice on the same instance");
+ if (!feedDataHosted) {
+ addHostedFeedData();
+ }
+
+ List<FeedItem> queue = new ArrayList<FeedItem>();
+
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ for (Feed feed : hostedFeeds) {
+ feed.setDownloaded(true);
+ if (feed.getImage() != null) {
+ FeedImage image = feed.getImage();
+ image.setFile_url(image.getDownload_url());
+ image.setDownloaded(true);
+ }
+ if (downloadEpisodes) {
+ for (FeedItem item : feed.getItems()) {
+ if (item.hasMedia()) {
+ FeedMedia media = item.getMedia();
+ int fileId = Integer.parseInt(StringUtils.substringAfter(media.getDownload_url(), "files/"));
+ media.setFile_url(server.accessFile(fileId).getAbsolutePath());
+ media.setDownloaded(true);
+ }
+ }
+ }
+
+ queue.add(feed.getItems().get(0));
+ feed.getItems().get(1).getMedia().setPlaybackCompletionDate(new Date());
+ }
+ adapter.setCompleteFeed(hostedFeeds.toArray(new Feed[hostedFeeds.size()]));
+ adapter.setQueue(queue);
+ adapter.close();
+ EventDistributor.getInstance().sendFeedUpdateBroadcast();
+ EventDistributor.getInstance().sendQueueUpdateBroadcast();
+ }
+}
diff --git a/src/instrumentationTest/de/test/antennapod/ui/UITestUtilsTest.java b/src/instrumentationTest/de/test/antennapod/ui/UITestUtilsTest.java
new file mode 100644
index 000000000..88180152c
--- /dev/null
+++ b/src/instrumentationTest/de/test/antennapod/ui/UITestUtilsTest.java
@@ -0,0 +1,94 @@
+package instrumentationTest.de.test.antennapod.ui;
+
+import android.test.InstrumentationTestCase;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.feed.FeedItem;
+import org.apache.http.HttpStatus;
+
+import java.io.File;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+
+/**
+ * Test for the UITestUtils. Makes sure that all URLs are reachable and that the class does not cause any crashes.
+ */
+public class UITestUtilsTest extends InstrumentationTestCase {
+
+ private UITestUtils uiTestUtils;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ uiTestUtils = new UITestUtils(getInstrumentation().getTargetContext());
+ uiTestUtils.setup();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+ uiTestUtils.tearDown();
+ }
+
+ public void testAddHostedFeeds() throws Exception {
+ uiTestUtils.addHostedFeedData();
+ final List<Feed> feeds = uiTestUtils.hostedFeeds;
+ assertNotNull(feeds);
+ assertFalse(feeds.isEmpty());
+
+ for (Feed feed : feeds) {
+ testUrlReachable(feed.getDownload_url());
+ if (feed.getImage() != null) {
+ testUrlReachable(feed.getImage().getDownload_url());
+ }
+ for (FeedItem item : feed.getItems()) {
+ if (item.hasMedia()) {
+ testUrlReachable(item.getMedia().getDownload_url());
+ }
+ }
+ }
+ }
+
+ private void testUrlReachable(String strUtl) throws Exception {
+ URL url = new URL(strUtl);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("GET");
+ conn.connect();
+ int rc = conn.getResponseCode();
+ assertEquals(HttpStatus.SC_OK, rc);
+ conn.disconnect();
+ }
+
+ private void addLocalFeedDataCheck(boolean downloadEpisodes) throws Exception {
+ uiTestUtils.addLocalFeedData(downloadEpisodes);
+ assertNotNull(uiTestUtils.hostedFeeds);
+ assertFalse(uiTestUtils.hostedFeeds.isEmpty());
+
+ for (Feed feed : uiTestUtils.hostedFeeds) {
+ assertTrue(feed.getId() != 0);
+ if (feed.getImage() != null) {
+ assertTrue(feed.getImage().getId() != 0);
+ }
+ for (FeedItem item : feed.getItems()) {
+ assertTrue(item.getId() != 0);
+ if (item.hasMedia()) {
+ assertTrue(item.getMedia().getId() != 0);
+ if (downloadEpisodes) {
+ assertTrue(item.getMedia().isDownloaded());
+ assertNotNull(item.getMedia().getFile_url());
+ File file = new File(item.getMedia().getFile_url());
+ assertTrue(file.exists());
+ }
+ }
+ }
+ }
+ }
+
+ public void testAddLocalFeedDataNoDownload() throws Exception {
+ addLocalFeedDataCheck(false);
+ }
+
+ public void testAddLocalFeedDataDownload() throws Exception {
+ addLocalFeedDataCheck(true);
+ }
+}
diff --git a/src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java b/src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java
index 272bcda5e..fc5025b14 100644
--- a/src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java
+++ b/src/instrumentationTest/de/test/antennapod/util/service/download/HTTPBin.java
@@ -26,6 +26,8 @@ import java.util.zip.GZIPOutputStream;
public class HTTPBin extends NanoHTTPD {
private static final String TAG = "HTTPBin";
public static final int PORT = 8124;
+ public static final String BASE_URL = "http://127.0.0.1:" + HTTPBin.PORT;
+
private static final String MIME_HTML = "text/html";
private static final String MIME_PLAIN = "text/plain";
@@ -70,7 +72,7 @@ public class HTTPBin extends NanoHTTPD {
}
}
- private synchronized File accessFile(int id) {
+ public synchronized File accessFile(int id) {
if (id < 0 || id >= servedFiles.size()) {
return null;
} else {