summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java6
-rw-r--r--app/src/androidTest/java/de/test/antennapod/NthMatcher.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/playback/PlaybackBuiltinTest.java17
-rw-r--r--app/src/androidTest/java/de/test/antennapod/playback/PlaybackExoplayerTest.java17
-rw-r--r--app/src/androidTest/java/de/test/antennapod/playback/PlaybackSonicTest.java17
-rw-r--r--app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java (renamed from app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java)405
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java5
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java277
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java10
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java128
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java64
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java3
-rw-r--r--app/src/main/res/xml/preferences_playback.xml5
-rw-r--r--app/src/main/res/xml/preferences_user_interface.xml7
-rw-r--r--build.gradle1
-rw-r--r--config/checkstyle/checkstyle-best-practice.xml5
-rw-r--r--config/checkstyle/checkstyle.xml13
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/util/ImageResourceUtils.java45
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/util/PlaybackSpeedUtils.java (renamed from core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackSpeedHelper.java)12
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java19
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java24
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java4
-rw-r--r--core/src/main/res/drawable/borderless_button_dark.xml19
-rw-r--r--core/src/main/res/values-v16/colors.xml (renamed from core/src/main/res/values-v19/colors.xml)0
-rw-r--r--core/src/main/res/values/strings.xml4
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java73
47 files changed, 639 insertions, 625 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java b/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
index f895b4d5e..2ce42be6d 100644
--- a/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java
@@ -6,6 +6,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.espresso.PerformException;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
+import androidx.test.espresso.ViewInteraction;
import androidx.test.espresso.contrib.DrawerActions;
import androidx.test.espresso.contrib.RecyclerViewActions;
import androidx.test.espresso.util.HumanReadables;
@@ -26,6 +27,7 @@ import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.Matchers.allOf;
public class EspressoTestUtils {
/**
@@ -127,4 +129,8 @@ public class EspressoTestUtils {
onView(isRoot()).perform(waitForView(withId(R.id.drawer_layout), 1000));
onView(withId(R.id.drawer_layout)).perform(DrawerActions.close());
}
+
+ public static ViewInteraction onDrawerItem(Matcher<View> viewMatcher) {
+ return onView(allOf(viewMatcher, withId(R.id.txtvTitle)));
+ }
}
diff --git a/app/src/androidTest/java/de/test/antennapod/NthMatcher.java b/app/src/androidTest/java/de/test/antennapod/NthMatcher.java
index f9ecacda5..3f2b83a26 100644
--- a/app/src/androidTest/java/de/test/antennapod/NthMatcher.java
+++ b/app/src/androidTest/java/de/test/antennapod/NthMatcher.java
@@ -15,7 +15,7 @@ public class NthMatcher {
return nth(matcher, 2);
}
- private static <T> Matcher<T> nth(final Matcher<T> matcher, final int index) {
+ public static <T> Matcher<T> nth(final Matcher<T> matcher, final int index) {
return new BaseMatcher<T>() {
AtomicInteger count = new AtomicInteger(0);
diff --git a/app/src/androidTest/java/de/test/antennapod/playback/PlaybackBuiltinTest.java b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackBuiltinTest.java
new file mode 100644
index 000000000..a80ee41d7
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackBuiltinTest.java
@@ -0,0 +1,17 @@
+package de.test.antennapod.playback;
+
+import androidx.test.filters.LargeTest;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import org.junit.Before;
+
+/**
+ * Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity.
+ */
+@LargeTest
+public class PlaybackBuiltinTest extends PlaybackTest {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ UserPreferences.enableBuiltin();
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/playback/PlaybackExoplayerTest.java b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackExoplayerTest.java
new file mode 100644
index 000000000..0cf73f069
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackExoplayerTest.java
@@ -0,0 +1,17 @@
+package de.test.antennapod.playback;
+
+import androidx.test.filters.LargeTest;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import org.junit.Before;
+
+/**
+ * Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity.
+ */
+@LargeTest
+public class PlaybackExoplayerTest extends PlaybackTest {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ UserPreferences.enableExoplayer();
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/playback/PlaybackSonicTest.java b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackSonicTest.java
new file mode 100644
index 000000000..a0fb74809
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackSonicTest.java
@@ -0,0 +1,17 @@
+package de.test.antennapod.playback;
+
+import androidx.test.filters.LargeTest;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import org.junit.Before;
+
+/**
+ * Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity.
+ */
+@LargeTest
+public class PlaybackSonicTest extends PlaybackTest {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ UserPreferences.enableSonic();
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java
index ec5dc804e..78f1ba7c4 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java
@@ -1,26 +1,11 @@
-package de.test.antennapod.ui;
+package de.test.antennapod.playback;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
-import android.view.View;
-import android.widget.ListView;
-
-import com.robotium.solo.Solo;
-import com.robotium.solo.Timeout;
-
-import org.awaitility.Awaitility;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import java.util.List;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -29,59 +14,58 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
+import de.test.antennapod.EspressoTestUtils;
+import de.test.antennapod.ui.UITestUtils;
+import org.awaitility.Awaitility;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static de.test.antennapod.EspressoTestUtils.onDrawerItem;
+import static de.test.antennapod.EspressoTestUtils.openNavDrawer;
+import static de.test.antennapod.EspressoTestUtils.waitForView;
+import static de.test.antennapod.NthMatcher.first;
+import static de.test.antennapod.NthMatcher.nth;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
/**
* test cases for starting and ending playback from the MainActivity and AudioPlayerActivity
*/
-@LargeTest
-public class PlaybackTest {
- private static final int EPISODES_DRAWER_LIST_INDEX = 1;
- private static final int QUEUE_DRAWER_LIST_INDEX = 0;
+public abstract class PlaybackTest {
@Rule
- public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class);
+ public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class, false, false);
- private Solo solo;
private UITestUtils uiTestUtils;
- private Context context;
+ protected Context context;
@Before
public void setUp() throws Exception {
- context = InstrumentationRegistry.getTargetContext();
-
- PodDBAdapter.init(context);
- PodDBAdapter.deleteDatabase();
-
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- prefs.edit()
- .clear()
- .putBoolean(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT, false)
- .putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false)
- .commit();
-
- solo = new Solo(InstrumentationRegistry.getInstrumentation(), getActivity());
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ EspressoTestUtils.clearPreferences();
+ EspressoTestUtils.clearDatabase();
+ EspressoTestUtils.makeNotFirstRun();
uiTestUtils = new UITestUtils(context);
uiTestUtils.setup();
-
- // create database
- PodDBAdapter adapter = PodDBAdapter.getInstance();
- adapter.open();
- adapter.close();
}
@After
public void tearDown() throws Exception {
- solo.finishOpenedActivities();
uiTestUtils.tearDown();
// shut down playback service
@@ -89,26 +73,139 @@ public class PlaybackTest {
context.sendBroadcast(new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
}
- private MainActivity getActivity() {
- return activityTestRule.getActivity();
+ @Test
+ public void testContinousPlaybackOffMultipleEpisodes() throws Exception {
+ setContinuousPlaybackPreference(false);
+ uiTestUtils.addLocalFeedData(true);
+ activityTestRule.launchActivity(new Intent());
+ List<FeedItem> queue = DBReader.getQueue();
+ final FeedItem first = queue.get(0);
+ playFromQueue(0);
+ Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> {
+ if (uiTestUtils.getPlaybackController(getActivity()).getStatus()
+ != PlayerStatus.PLAYING) {
+ return true;
+ } else if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
+ return uiTestUtils.getCurrentMedia(getActivity()).getId()
+ != first.getMedia().getId();
+ } else {
+ return true;
+ }
+ });
+
+ Thread.sleep(1000);
+ assertNotEquals(PlayerStatus.PLAYING, uiTestUtils.getPlaybackController(getActivity()).getStatus());
}
- private void openNavDrawer() {
- solo.clickOnImageButton(0);
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ @Test
+ public void testContinuousPlaybackOnMultipleEpisodes() throws Exception {
+ setContinuousPlaybackPreference(true);
+ uiTestUtils.addLocalFeedData(true);
+ activityTestRule.launchActivity(new Intent());
+
+ List<FeedItem> queue = DBReader.getQueue();
+ final FeedItem first = queue.get(0);
+ final FeedItem second = queue.get(1);
+
+ playFromQueue(0);
+ Awaitility.await().atMost(2, TimeUnit.SECONDS).until(() -> {
+ if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
+ return uiTestUtils.getCurrentMedia(getActivity()).getId()
+ == first.getMedia().getId();
+ } else {
+ return false;
+ }
+ });
+ Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() -> {
+ if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
+ return uiTestUtils.getCurrentMedia(getActivity()).getId()
+ == second.getMedia().getId();
+ } else {
+ return false;
+ }
+ });
+ }
+
+
+ @Test
+ public void testReplayEpisodeContinuousPlaybackOn() throws Exception {
+ replayEpisodeCheck(true);
+ }
+
+ @Test
+ public void testReplayEpisodeContinuousPlaybackOff() throws Exception {
+ replayEpisodeCheck(false);
+ }
+
+ @Test
+ public void testSmartMarkAsPlayed_Skip_Average() throws Exception {
+ doTestSmartMarkAsPlayed_Skip_ForEpisode(0);
+ }
+
+ @Test
+ public void testSmartMarkAsPlayed_Skip_LastEpisodeInQueue() throws Exception {
+ doTestSmartMarkAsPlayed_Skip_ForEpisode(-1);
+ }
+
+ @Test
+ public void testSmartMarkAsPlayed_Pause_WontAffectItem() throws Exception {
+ setSmartMarkAsPlayedPreference(60);
+
+ uiTestUtils.addLocalFeedData(true);
+ activityTestRule.launchActivity(new Intent());
+
+ final int fiIdx = 0;
+ final FeedItem feedItem = DBReader.getQueue().get(fiIdx);
+
+ playFromQueue(fiIdx);
+
+ // let playback run a bit then pause
+ Awaitility.await()
+ .atMost(1000, MILLISECONDS)
+ .until(() -> PlayerStatus.PLAYING == uiTestUtils.getPlaybackController(getActivity()).getStatus());
+ pauseEpisode();
+ Awaitility.await()
+ .atMost(1000, MILLISECONDS)
+ .until(() -> PlayerStatus.PAUSED == uiTestUtils.getPlaybackController(getActivity()).getStatus());
+
+ assertThat("Ensure even with smart mark as play, after pause, the item remains in the queue.",
+ DBReader.getQueue(), hasItems(feedItem));
+ assertThat("Ensure even with smart mark as play, after pause, the item played status remains false.",
+ DBReader.getFeedItem(feedItem.getId()).isPlayed(), is(false));
}
- private void setContinuousPlaybackPreference(boolean value) {
+ @Test
+ public void testStartLocal() throws Exception {
+ uiTestUtils.addLocalFeedData(true);
+ activityTestRule.launchActivity(new Intent());
+ DBWriter.clearQueue().get();
+ startLocalPlayback();
+ }
+
+ @Test
+ public void testContinousPlaybackOffSingleEpisode() throws Exception {
+ setContinuousPlaybackPreference(false);
+ uiTestUtils.addLocalFeedData(true);
+ activityTestRule.launchActivity(new Intent());
+ DBWriter.clearQueue().get();
+ startLocalPlayback();
+ }
+
+ protected MainActivity getActivity() {
+ return activityTestRule.getActivity();
+ }
+
+ protected void setContinuousPlaybackPreference(boolean value) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putBoolean(UserPreferences.PREF_FOLLOW_QUEUE, value).commit();
}
- private void setSkipKeepsEpisodePreference(boolean value) {
+ protected void setSkipKeepsEpisodePreference(boolean value) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putBoolean(UserPreferences.PREF_SKIP_KEEPS_EPISODE, value).commit();
}
- private void setSmartMarkAsPlayedPreference(int smartMarkAsPlayedSecs) {
+ protected void setSmartMarkAsPlayedPreference(int smartMarkAsPlayedSecs) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putString(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS,
Integer.toString(smartMarkAsPlayedSecs, 10))
@@ -120,206 +217,88 @@ public class PlaybackTest {
context.sendBroadcast(skipIntent);
}
- private void pauseEpisode() {
+ protected void pauseEpisode() {
Intent pauseIntent = new Intent(PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE);
context.sendBroadcast(pauseIntent);
}
- private void startLocalPlayback() {
+ protected void startLocalPlayback() {
openNavDrawer();
- // if we try to just click on plain old text then
- // we might wind up clicking on the fragment title and not
- // the drawer element like we want.
- ListView drawerView = (ListView)solo.getView(R.id.nav_list);
- // this should be 'Episodes'
- View targetView = drawerView.getChildAt(EPISODES_DRAWER_LIST_INDEX);
- solo.waitForView(targetView);
- solo.clickOnView(targetView);
- solo.waitForText(solo.getString(R.string.all_episodes_short_label));
- solo.clickOnText(solo.getString(R.string.all_episodes_short_label));
+ onDrawerItem(withText(R.string.episodes_label)).perform(click());
+ onView(isRoot()).perform(waitForView(withId(R.id.emptyViewTitle), 1000));
+ onView(withText(R.string.all_episodes_short_label)).perform(click());
final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(0, 10);
- assertTrue(solo.waitForView(solo.getView(R.id.butSecondaryAction)));
+ onView(isRoot()).perform(waitForView(withId(R.id.butSecondaryAction), 1000));
- solo.clickOnView(solo.getView(R.id.butSecondaryAction));
+ onView(first(withId(R.id.butSecondaryAction))).perform(click());
long mediaId = episodes.get(0).getMedia().getId();
- boolean playing = solo.waitForCondition(() -> {
+ Awaitility.await().atMost(1, TimeUnit.SECONDS).until(() -> {
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
} else {
return false;
}
- }, Timeout.getSmallTimeout());
- assertTrue(playing);
- }
-
- private void startLocalPlaybackFromQueue() {
- gotoQueueScreen();
- playFromQueue(0);
- }
-
- private void gotoQueueScreen() {
- openNavDrawer();
- // if we try to just click on plain old text then
- // we might wind up clicking on the fragment title and not
- // the drawer element like we want.
- ListView drawerView = (ListView)solo.getView(R.id.nav_list);
- // this should be 'Queue'
- View targetView = drawerView.getChildAt(QUEUE_DRAWER_LIST_INDEX);
- solo.waitForView(targetView);
- solo.clickOnView(targetView);
- assertTrue(solo.waitForView(solo.getView(R.id.butSecondaryAction)));
+ });
}
/**
*
* @param itemIdx The 0-based index of the episode to be played in the queue.
*/
- private void playFromQueue(int itemIdx) {
+ protected void playFromQueue(int itemIdx) {
final List<FeedItem> queue = DBReader.getQueue();
- solo.clickOnImageButton(itemIdx + 1);
- assertTrue(solo.waitForView(solo.getView(R.id.butPlay)));
- long mediaId = queue.get(itemIdx).getMedia().getId();
- boolean playing = solo.waitForCondition(() -> {
- if(uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
- } else {
- return false;
- }
- }, Timeout.getSmallTimeout());
-
- assertTrue(playing);
- }
-
- @Test
- public void testStartLocal() throws Exception {
- uiTestUtils.addLocalFeedData(true);
- DBWriter.clearQueue().get();
- startLocalPlayback();
- }
-
- @Test
- public void testContinousPlaybackOffSingleEpisode() throws Exception {
- setContinuousPlaybackPreference(false);
- uiTestUtils.addLocalFeedData(true);
- DBWriter.clearQueue().get();
- startLocalPlayback();
- }
-
- @Test
- public void testContinousPlaybackOffMultipleEpisodes() throws Exception {
- setContinuousPlaybackPreference(false);
- uiTestUtils.addLocalFeedData(true);
- List<FeedItem> queue = DBReader.getQueue();
- final FeedItem first = queue.get(0);
- startLocalPlaybackFromQueue();
- boolean stopped = solo.waitForCondition(() -> {
- if (uiTestUtils.getPlaybackController(getActivity()).getStatus()
- != PlayerStatus.PLAYING) {
- return true;
- } else if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId()
- != first.getMedia().getId();
- } else {
- return true;
- }
- }, Timeout.getSmallTimeout());
- assertTrue(stopped);
- Thread.sleep(1000);
- PlayerStatus status = uiTestUtils.getPlaybackController(getActivity()).getStatus();
- assertFalse(status.equals(PlayerStatus.PLAYING));
- }
-
- @Test
- public void testContinuousPlaybackOnMultipleEpisodes() throws Exception {
- setContinuousPlaybackPreference(true);
- uiTestUtils.addLocalFeedData(true);
- List<FeedItem> queue = DBReader.getQueue();
- final FeedItem first = queue.get(0);
- final FeedItem second = queue.get(1);
- startLocalPlaybackFromQueue();
- boolean firstPlaying = solo.waitForCondition(() -> {
- if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId()
- == first.getMedia().getId();
- } else {
- return false;
- }
- }, Timeout.getSmallTimeout());
- assertTrue(firstPlaying);
- boolean secondPlaying = solo.waitForCondition(() -> {
+ onView(nth(withId(R.id.butSecondaryAction), itemIdx + 1)).perform(click());
+ onView(isRoot()).perform(waitForView(withId(R.id.butPlay), 1000));
+ long mediaId = queue.get(itemIdx).getMedia().getId();
+ Awaitility.await().atMost(1, TimeUnit.SECONDS).until(() -> {
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId()
- == second.getMedia().getId();
+ return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
} else {
return false;
}
- }, Timeout.getLargeTimeout());
- assertTrue(secondPlaying);
+ });
}
/**
* Check if an episode can be played twice without problems.
*/
- private void replayEpisodeCheck(boolean followQueue) throws Exception {
+ protected void replayEpisodeCheck(boolean followQueue) throws Exception {
setContinuousPlaybackPreference(followQueue);
uiTestUtils.addLocalFeedData(true);
DBWriter.clearQueue().get();
+ activityTestRule.launchActivity(new Intent());
final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(0, 10);
startLocalPlayback();
long mediaId = episodes.get(0).getMedia().getId();
- boolean startedPlaying = solo.waitForCondition(() -> {
+ Awaitility.await().atMost(1, TimeUnit.SECONDS).until(() -> {
if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
} else {
return false;
}
- }, Timeout.getSmallTimeout());
- assertTrue(startedPlaying);
+ });
- boolean stoppedPlaying = solo.waitForCondition(() ->
+ Awaitility.await().atMost(5, TimeUnit.SECONDS).until(() ->
uiTestUtils.getCurrentMedia(getActivity()) == null
- || uiTestUtils.getCurrentMedia(getActivity()).getId() != mediaId, Timeout.getLargeTimeout());
- assertTrue(stoppedPlaying);
+ || uiTestUtils.getCurrentMedia(getActivity()).getId() != mediaId);
startLocalPlayback();
- boolean startedReplay = solo.waitForCondition(() -> {
- if(uiTestUtils.getCurrentMedia(getActivity()) != null) {
+ Awaitility.await().atMost(1, TimeUnit.SECONDS).until(() -> {
+ if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
} else {
return false;
}
- }, Timeout.getLargeTimeout());
- assertTrue(startedReplay);
- }
-
- @Test
- public void testReplayEpisodeContinuousPlaybackOn() throws Exception {
- replayEpisodeCheck(true);
- }
-
- @Test
- public void testReplayEpisodeContinuousPlaybackOff() throws Exception {
- replayEpisodeCheck(false);
- }
-
- @Test
- public void testSmartMarkAsPlayed_Skip_Average() throws Exception {
- doTestSmartMarkAsPlayed_Skip_ForEpisode(0);
- }
-
- @Test
- public void testSmartMarkAsPlayed_Skip_LastEpisodeInQueue() throws Exception {
- doTestSmartMarkAsPlayed_Skip_ForEpisode(-1);
+ });
}
- private void doTestSmartMarkAsPlayed_Skip_ForEpisode(int itemIdxNegAllowed) throws Exception {
+ protected void doTestSmartMarkAsPlayed_Skip_ForEpisode(int itemIdxNegAllowed) throws Exception {
setSmartMarkAsPlayedPreference(60);
// ensure when an episode is skipped, it is removed due to smart as played
setSkipKeepsEpisodePreference(false);
-
uiTestUtils.addLocalFeedData(true);
int fiIdx;
@@ -330,7 +309,7 @@ public class PlaybackTest {
}
final FeedItem feedItem = DBReader.getQueue().get(fiIdx);
- gotoQueueScreen();
+ activityTestRule.launchActivity(new Intent());
playFromQueue(fiIdx);
skipEpisode();
@@ -344,32 +323,4 @@ public class PlaybackTest {
});
assertThat(DBReader.getFeedItem(feedItem.getId()).isPlayed(), is(true));
}
-
- @Test
- public void testSmartMarkAsPlayed_Pause_WontAffectItem() throws Exception {
- setSmartMarkAsPlayedPreference(60);
-
- uiTestUtils.addLocalFeedData(true);
-
- final int fiIdx = 0;
- final FeedItem feedItem = DBReader.getQueue().get(fiIdx);
-
- gotoQueueScreen();
- playFromQueue(fiIdx);
-
- // let playback run a bit then pause
- Awaitility.await()
- .atMost(1000, MILLISECONDS)
- .until(() -> PlayerStatus.PLAYING == uiTestUtils.getPlaybackController(getActivity()).getStatus());
- pauseEpisode();
- Awaitility.await()
- .atMost(1000, MILLISECONDS)
- .until(() -> PlayerStatus.PAUSED == uiTestUtils.getPlaybackController(getActivity()).getStatus());
-
- assertThat("Ensure even with smart mark as play, after pause, the item remains in the queue.",
- DBReader.getQueue(), hasItems(feedItem));
- assertThat("Ensure even with smart mark as play, after pause, the item played status remains false.",
- DBReader.getFeedItem(feedItem.getId()).isPlayed(), is(false));
- }
-
}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
index 360b55ce6..963a39064 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java
@@ -38,6 +38,7 @@ import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static de.test.antennapod.EspressoTestUtils.onDrawerItem;
import static de.test.antennapod.EspressoTestUtils.waitForView;
import static de.test.antennapod.NthMatcher.first;
import static junit.framework.TestCase.assertTrue;
@@ -75,10 +76,6 @@ public class NavigationDrawerTest {
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
}
- private ViewInteraction onDrawerItem(Matcher<View> viewMatcher) {
- return onView(allOf(viewMatcher, withId(R.id.txtvTitle)));
- }
-
@Test
public void testClickNavDrawer() throws Exception {
uiTestUtils.addLocalFeedData(false);
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
deleted file mode 100644
index 5b3530ea8..000000000
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java
+++ /dev/null
@@ -1,277 +0,0 @@
-package de.test.antennapod.ui;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
-import android.view.View;
-import android.widget.ListView;
-
-import com.robotium.solo.Solo;
-import com.robotium.solo.Timeout;
-
-import java.util.List;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.service.playback.PlayerStatus;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.test.antennapod.EspressoTestUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * test cases for starting and ending playback from the MainActivity and AudioPlayerActivity
- */
-@LargeTest
-public class PlaybackSonicTest {
- private static final int EPISODES_DRAWER_LIST_INDEX = 1;
- private static final int QUEUE_DRAWER_LIST_INDEX = 0;
-
- private Solo solo;
- private UITestUtils uiTestUtils;
-
- private Context context;
-
- @Rule
- public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class, false, false);
-
- @Before
- public void setUp() throws Exception {
- EspressoTestUtils.clearPreferences();
- EspressoTestUtils.makeNotFirstRun();
- EspressoTestUtils.clearDatabase();
- context = InstrumentationRegistry.getTargetContext();
-
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- prefs.edit()
- .clear()
- .putBoolean(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT, false)
- .putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false)
- .putString(UserPreferences.PREF_MEDIA_PLAYER, "sonic")
- .commit();
-
- activityTestRule.launchActivity(new Intent());
- solo = new Solo(getInstrumentation(), activityTestRule.getActivity());
-
- uiTestUtils = new UITestUtils(context);
- uiTestUtils.setup();
- }
-
- @After
- public void tearDown() throws Exception {
- solo.finishOpenedActivities();
- uiTestUtils.tearDown();
-
- // shut down playback service
- skipEpisode();
- context.sendBroadcast(new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
- }
-
- private MainActivity getActivity() {
- return activityTestRule.getActivity();
- }
-
- private void openNavDrawer() {
- solo.clickOnImageButton(0);
- getInstrumentation().waitForIdleSync();
- }
-
- private void setContinuousPlaybackPreference(boolean value) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- prefs.edit().putBoolean(UserPreferences.PREF_FOLLOW_QUEUE, value).commit();
- }
-
- private void skipEpisode() {
- Intent skipIntent = new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE);
- context.sendBroadcast(skipIntent);
- }
-
- private void startLocalPlayback() {
- openNavDrawer();
- // if we try to just click on plain old text then
- // we might wind up clicking on the fragment title and not
- // the drawer element like we want.
- ListView drawerView = (ListView)solo.getView(R.id.nav_list);
- // this should be 'Episodes'
- View targetView = drawerView.getChildAt(EPISODES_DRAWER_LIST_INDEX);
- solo.waitForView(targetView);
- solo.clickOnView(targetView);
- getInstrumentation().waitForIdleSync();
- solo.waitForText(solo.getString(R.string.all_episodes_short_label));
- solo.clickOnText(solo.getString(R.string.all_episodes_short_label));
- getInstrumentation().waitForIdleSync();
-
- final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(0, 10);
- assertTrue(solo.waitForView(solo.getView(R.id.butSecondaryAction)));
-
- solo.clickOnView(solo.getView(R.id.butSecondaryAction));
- long mediaId = episodes.get(0).getMedia().getId();
- boolean playing = solo.waitForCondition(() -> {
- if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
- } else {
- return false;
- }
- }, Timeout.getSmallTimeout());
- assertTrue(playing);
- }
-
- private void startLocalPlaybackFromQueue() {
- openNavDrawer();
-
- // if we try to just click on plain old text then
- // we might wind up clicking on the fragment title and not
- // the drawer element like we want.
- ListView drawerView = (ListView)solo.getView(R.id.nav_list);
- // this should be 'Queue'
- View targetView = drawerView.getChildAt(QUEUE_DRAWER_LIST_INDEX);
- solo.waitForView(targetView);
- getInstrumentation().waitForIdleSync();
- solo.clickOnView(targetView);
- assertTrue(solo.waitForView(solo.getView(R.id.butSecondaryAction)));
-
- final List<FeedItem> queue = DBReader.getQueue();
- solo.clickOnImageButton(1);
- assertTrue(solo.waitForView(solo.getView(R.id.butPlay)));
- long mediaId = queue.get(0).getMedia().getId();
- boolean playing = solo.waitForCondition(() -> {
- if(uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
- } else {
- return false;
- }
- }, Timeout.getSmallTimeout());
- assertTrue(playing);
- }
-
- @Test
- public void testStartLocal() throws Exception {
- uiTestUtils.addLocalFeedData(true);
- DBWriter.clearQueue().get();
- startLocalPlayback();
- }
-
- @Test
- public void testContinousPlaybackOffSingleEpisode() throws Exception {
- setContinuousPlaybackPreference(false);
- uiTestUtils.addLocalFeedData(true);
- DBWriter.clearQueue().get();
- startLocalPlayback();
- }
-
- @Test
- public void testContinousPlaybackOffMultipleEpisodes() throws Exception {
- setContinuousPlaybackPreference(false);
- uiTestUtils.addLocalFeedData(true);
- List<FeedItem> queue = DBReader.getQueue();
- final FeedItem first = queue.get(0);
-
- startLocalPlaybackFromQueue();
- boolean stopped = solo.waitForCondition(() -> {
- if (uiTestUtils.getPlaybackController(getActivity()).getStatus()
- != PlayerStatus.PLAYING) {
- return true;
- } else if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId()
- != first.getMedia().getId();
- } else {
- return true;
- }
- }, Timeout.getSmallTimeout());
- assertTrue(stopped);
- Thread.sleep(1000);
- PlayerStatus status = uiTestUtils.getPlaybackController(getActivity()).getStatus();
- assertFalse(status.equals(PlayerStatus.PLAYING));
- }
-
- @Test
- public void testContinuousPlaybackOnMultipleEpisodes() throws Exception {
- setContinuousPlaybackPreference(true);
- uiTestUtils.addLocalFeedData(true);
- List<FeedItem> queue = DBReader.getQueue();
- final FeedItem first = queue.get(0);
- final FeedItem second = queue.get(1);
-
- startLocalPlaybackFromQueue();
- boolean firstPlaying = solo.waitForCondition(() -> {
- if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId()
- == first.getMedia().getId();
- } else {
- return false;
- }
- }, Timeout.getSmallTimeout());
- assertTrue(firstPlaying);
- boolean secondPlaying = solo.waitForCondition(() -> {
- if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId()
- == second.getMedia().getId();
- } else {
- return false;
- }
- }, Timeout.getLargeTimeout());
- assertTrue(secondPlaying);
- }
-
- /**
- * Check if an episode can be played twice without problems.
- */
- private void replayEpisodeCheck(boolean followQueue) throws Exception {
- setContinuousPlaybackPreference(followQueue);
- uiTestUtils.addLocalFeedData(true);
- DBWriter.clearQueue().get();
- final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(0, 10);
-
- startLocalPlayback();
- long mediaId = episodes.get(0).getMedia().getId();
- boolean startedPlaying = solo.waitForCondition(() -> {
- if (uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
- } else {
- return false;
- }
- }, Timeout.getSmallTimeout());
- assertTrue(startedPlaying);
-
- boolean stoppedPlaying = solo.waitForCondition(() ->
- uiTestUtils.getCurrentMedia(getActivity()) == null
- || uiTestUtils.getCurrentMedia(getActivity()).getId() != mediaId
- , Timeout.getLargeTimeout());
- assertTrue(stoppedPlaying);
-
- startLocalPlayback();
- boolean startedReplay = solo.waitForCondition(() -> {
- if(uiTestUtils.getCurrentMedia(getActivity()) != null) {
- return uiTestUtils.getCurrentMedia(getActivity()).getId() == mediaId;
- } else {
- return false;
- }
- }, Timeout.getLargeTimeout());
- assertTrue(startedReplay);
- }
-
- @Test
- public void testReplayEpisodeContinuousPlaybackOn() throws Exception {
- replayEpisodeCheck(true);
- }
-
- @Test
- public void testReplayEpisodeContinuousPlaybackOff() throws Exception {
- replayEpisodeCheck(false);
- }
-
-}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java b/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
index 7f0bf8fa2..37d76bb6d 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java
@@ -15,17 +15,20 @@ import org.junit.runner.RunWith;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.endsWith;
/**
- * User interface tests for queue fragment
+ * User interface tests for queue fragment.
*/
@RunWith(AndroidJUnit4.class)
public class QueueFragmentTest {
@Rule
- public IntentsTestRule<MainActivity> mActivityRule = new IntentsTestRule<>(MainActivity.class, false, false);
+ public IntentsTestRule<MainActivity> activityRule = new IntentsTestRule<>(MainActivity.class, false, false);
@Before
public void setUp() {
@@ -33,12 +36,13 @@ public class QueueFragmentTest {
EspressoTestUtils.makeNotFirstRun();
EspressoTestUtils.clearDatabase();
EspressoTestUtils.setLastNavFragment(QueueFragment.TAG);
- mActivityRule.launchActivity(new Intent());
+ activityRule.launchActivity(new Intent());
}
@Test
public void testLockEmptyQueue() {
onView(withContentDescription(R.string.lock_queue)).perform(click());
+ onView(allOf(withClassName(endsWith("Button")), withText(R.string.lock_queue))).perform(click());
onView(withContentDescription(R.string.unlock_queue)).perform(click());
}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
index 905c65c34..82dc63d68 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
@@ -34,7 +34,7 @@ import org.junit.Assert;
* Utility methods for UI tests.
* Starts a web server that hosts feeds, episodes and images.
*/
-class UITestUtils {
+public class UITestUtils {
private static final String TAG = UITestUtils.class.getSimpleName();
diff --git a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
index f2dfca92e..d33eb55b8 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
@@ -1,7 +1,7 @@
package de.test.antennapod.util;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
+import android.content.Context;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import android.text.TextUtils;
@@ -13,77 +13,79 @@ import org.junit.After;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@SmallTest
public class FilenameGeneratorTest {
- private static final String VALID1 = "abc abc";
- private static final String INVALID1 = "ab/c: <abc";
- private static final String INVALID2 = "abc abc ";
+ private static final String VALID1 = "abc abc";
+ private static final String INVALID1 = "ab/c: <abc";
+ private static final String INVALID2 = "abc abc ";
public FilenameGeneratorTest() {
super();
}
@Test
- public void testGenerateFileName() throws IOException {
- String result = FileNameGenerator.generateFileName(VALID1);
- assertEquals(result, VALID1);
- createFiles(result);
- }
-
- @Test
- public void testGenerateFileName1() throws IOException {
- String result = FileNameGenerator.generateFileName(INVALID1);
- assertEquals(result, VALID1);
- createFiles(result);
- }
-
- @Test
- public void testGenerateFileName2() throws IOException {
- String result = FileNameGenerator.generateFileName(INVALID2);
- assertEquals(result, VALID1);
- createFiles(result);
- }
-
- @Test
- public void testFeedTitleContainsApostrophe() {
- String result = FileNameGenerator.generateFileName("Feed's Title ...");
- assertEquals("Feeds Title", result);
- }
-
- @Test
- public void testFeedTitleContainsDash() {
- String result = FileNameGenerator.generateFileName("Left - Right");
- assertEquals("Left - Right", result);
- }
-
- @Test
- public void testInvalidInput() {
- String result = FileNameGenerator.generateFileName("???");
- assertTrue(!TextUtils.isEmpty(result));
- }
-
- /**
- * Tests if files can be created.
- *
- * @throws IOException
- */
- private void createFiles(String name) throws IOException {
- File cache = InstrumentationRegistry.getContext().getExternalCacheDir();
- File testFile = new File(cache, name);
- testFile.mkdir();
- assertTrue(testFile.exists());
- testFile.delete();
- assertTrue(testFile.createNewFile());
-
- }
-
- @After
- public void tearDown() throws Exception {
- File f = new File(InstrumentationRegistry.getContext().getExternalCacheDir(), VALID1);
- f.delete();
- }
+ public void testGenerateFileName() throws IOException {
+ String result = FileNameGenerator.generateFileName(VALID1);
+ assertEquals(result, VALID1);
+ createFiles(result);
+ }
+
+ @Test
+ public void testGenerateFileName1() throws IOException {
+ String result = FileNameGenerator.generateFileName(INVALID1);
+ assertEquals(result, VALID1);
+ createFiles(result);
+ }
+
+ @Test
+ public void testGenerateFileName2() throws IOException {
+ String result = FileNameGenerator.generateFileName(INVALID2);
+ assertEquals(result, VALID1);
+ createFiles(result);
+ }
+
+ @Test
+ public void testFeedTitleContainsApostrophe() {
+ String result = FileNameGenerator.generateFileName("Feed's Title ...");
+ assertEquals("Feeds Title", result);
+ }
+
+ @Test
+ public void testFeedTitleContainsDash() {
+ String result = FileNameGenerator.generateFileName("Left - Right");
+ assertEquals("Left - Right", result);
+ }
+
+ @Test
+ public void testInvalidInput() {
+ String result = FileNameGenerator.generateFileName("???");
+ assertFalse(TextUtils.isEmpty(result));
+ }
+
+ /**
+ * Tests if files can be created.
+ *
+ * @throws IOException
+ */
+ private void createFiles(String name) throws IOException {
+ File cache = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalCacheDir();
+ File testFile = new File(cache, name);
+ testFile.mkdir();
+ assertTrue(testFile.exists());
+ testFile.delete();
+ assertTrue(testFile.createNewFile());
+
+ }
+
+ @After
+ public void tearDown() {
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ File f = new File(context.getExternalCacheDir(), VALID1);
+ f.delete();
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 8eb0b1e0b..7f8c14b03 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -13,7 +13,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
@@ -83,7 +83,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity {
}
float speed = 1.0f;
if(controller.canSetPlaybackSpeed()) {
- speed = PlaybackSpeedHelper.getCurrentPlaybackSpeed(controller.getMedia());
+ speed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(controller.getMedia());
}
String speedStr = new DecimalFormat("0.00").format(speed);
txtvPlaybackSpeed.setText(speedStr);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index a060e258a..6b8fd459d 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -64,6 +64,7 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@@ -504,7 +505,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements
private static String getWebsiteLinkWithFallback(Playable media) {
if (media == null) {
return null;
- } else if (media.getWebsiteLink() != null) {
+ } else if (StringUtils.isNotBlank(media.getWebsiteLink())) {
return media.getWebsiteLink();
} else if (media instanceof FeedMedia) {
return FeedItemUtil.getLinkWithFallback(((FeedMedia)media).getItem());
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
index 5b735cd1f..fd669f3e6 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -35,6 +35,7 @@ import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.ThemeUtils;
@@ -194,7 +195,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.butSecondary.setTag(item);
new CoverLoader(mainActivityRef.get())
- .withUri(item.getImageLocation())
+ .withUri(ImageResourceUtils.getImageLocation(item))
.withFallbackUri(item.getFeed().getImageLocation())
.withPlaceholderView(holder.placeholder)
.withCoverView(holder.cover)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
index 98d55dd97..b083908a8 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
@@ -17,9 +17,9 @@ import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
/**
* Shows a list of downloaded episodes
@@ -79,7 +79,7 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
}
Glide.with(context)
- .load(item.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(item))
.apply(new RequestOptions()
.placeholder(R.color.light_gray)
.error(R.color.light_gray)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
index fcdcb4ba6..42f009c85 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -40,6 +40,7 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.ThemeUtils;
@@ -322,7 +323,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
butSecondary.setTag(item);
new CoverLoader(mainActivity.get())
- .withUri(item.getImageLocation())
+ .withUri(ImageResourceUtils.getImageLocation(item))
.withFallbackUri(item.getFeed().getImageLocation())
.withPlaceholderView(placeholder)
.withCoverView(cover)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
index 31e9fccb5..861c6a4be 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java
@@ -10,6 +10,7 @@ import android.widget.ImageButton;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DownloadRequester;
public abstract class ItemActionButton {
@@ -43,6 +44,8 @@ public abstract class ItemActionButton {
return new PlayActionButton(item);
} else if (isDownloadingMedia) {
return new CancelDownloadActionButton(item);
+ } else if (UserPreferences.streamOverDownload()) {
+ return new StreamActionButton(item);
} else if (MobileDownloadHelper.userAllowedMobileDownloads() || !MobileDownloadHelper.userChoseAddToQueue() || isInQueue) {
return new DownloadActionButton(item, isInQueue);
} else {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java
new file mode 100644
index 000000000..dc7fd1e7a
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/StreamActionButton.java
@@ -0,0 +1,64 @@
+package de.danoeh.antennapod.adapter.actionbutton;
+
+import android.content.Context;
+
+import androidx.annotation.AttrRes;
+import androidx.annotation.StringRes;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
+
+import static de.danoeh.antennapod.core.service.playback.PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE;
+import static de.danoeh.antennapod.core.service.playback.PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE;
+
+public class StreamActionButton extends ItemActionButton {
+
+ StreamActionButton(FeedItem item) {
+ super(item);
+ }
+
+ @Override
+ @StringRes
+ public int getLabel() {
+ return R.string.stream_label;
+ }
+
+ @Override
+ @AttrRes
+ public int getDrawable() {
+ FeedMedia media = item.getMedia();
+ if (media != null && media.isCurrentlyPlaying()) {
+ return R.attr.av_pause;
+ }
+ return R.attr.action_stream;
+ }
+
+ @Override
+ public void onClick(Context context) {
+ final FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+
+ if (media.isPlaying()) {
+ togglePlayPause(context, media);
+ } else {
+ DBTasks.playMedia(context, media, false, true, true);
+ }
+ }
+
+ private void togglePlayPause(Context context, FeedMedia media) {
+ new PlaybackServiceStarter(context, media)
+ .startWhenPrepared(true)
+ .shouldStream(true)
+ .start();
+
+ String pauseOrResume = media.isCurrentlyPlaying()
+ ? ACTION_PAUSE_PLAY_CURRENT_EPISODE : ACTION_RESUME_PLAY_CURRENT_EPISODE;
+ IntentUtils.sendLocalBroadcast(context, pauseOrResume);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
index f53dbe57a..f6783a584 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -11,7 +11,7 @@ import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import java.util.Locale;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.playback.Playable;
@@ -212,6 +212,6 @@ public class PlaybackControlsDialog extends DialogFragment {
media = controller.getMedia();
}
- return PlaybackSpeedHelper.getCurrentPlaybackSpeed(media);
+ return PlaybackSpeedUtils.getCurrentPlaybackSpeed(media);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
index cf9ee6c41..5467d71a8 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -15,6 +15,7 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import io.reactivex.Maybe;
@@ -70,7 +71,7 @@ public class CoverFragment extends Fragment {
txtvPodcastTitle.setText(media.getFeedTitle());
txtvEpisodeTitle.setText(media.getEpisodeTitle());
Glide.with(this)
- .load(media.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(media))
.apply(new RequestOptions()
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.dontAnimate()
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index bbc33c6ca..5a5bdc081 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -22,6 +22,7 @@ import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import io.reactivex.Maybe;
@@ -227,7 +228,7 @@ public class ExternalPlayerFragment extends Fragment {
onPositionObserverUpdate();
Glide.with(getActivity())
- .load(media.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(media))
.apply(new RequestOptions()
.placeholder(R.color.light_gray)
.error(R.color.light_gray)
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index f17f8c645..2f64ac106 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -62,6 +62,7 @@ import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
import de.danoeh.antennapod.core.util.Flavors;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
@@ -384,7 +385,7 @@ public class ItemFragment extends Fragment implements OnSwipeGesture {
}
Glide.with(getActivity())
- .load(item.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(item))
.apply(new RequestOptions()
.placeholder(R.color.light_gray)
.error(R.color.light_gray)
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index b550669f3..b8ae7bb5b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -44,7 +44,7 @@ import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
@@ -331,7 +331,7 @@ public class QueueFragment extends Fragment {
conDialog.createNewDialog().show();
return true;
case R.id.episode_actions:
- ((MainActivity) requireActivity()) .loadChildFragment(
+ ((MainActivity) requireActivity()).loadChildFragment(
EpisodesApplyActionFragment.newInstance(queue, ACTION_DELETE | ACTION_REMOVE_FROM_QUEUE));
return true;
case R.id.queue_sort_episode_title_asc:
@@ -637,7 +637,7 @@ public class QueueFragment extends Fragment {
if(queue.size() > 0) {
long timeLeft = 0;
for(FeedItem item : queue) {
- float playbackSpeed = PlaybackSpeedHelper.getCurrentPlaybackSpeed(item.getMedia());
+ float playbackSpeed = PlaybackSpeedUtils.getCurrentPlaybackSpeed(item.getMedia());
if(item.getMedia() != null) {
timeLeft +=
(long) ((item.getMedia().getDuration() - item.getMedia().getPosition())
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
index 440660942..34e8684ed 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
@@ -134,7 +134,8 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat {
builder1.show();
});
builder.onNegative((dialog, which) -> {
- int hourOfDay = 7, minute = 0;
+ int hourOfDay = 7;
+ int minute = 0;
int[] updateTime = UserPreferences.getUpdateTimeOfDay();
if (updateTime.length == 2) {
hourOfDay = updateTime[0];
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index 5d012168e..f7aae8cde 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -2,12 +2,13 @@ package de.danoeh.antennapod.menuhandler;
import android.content.Context;
import android.content.DialogInterface;
-import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import org.apache.commons.lang3.StringUtils;
+
import java.util.Set;
import de.danoeh.antennapod.R;
@@ -42,6 +43,10 @@ public class FeedMenuHandler {
Log.d(TAG, "Preparing options menu");
menu.findItem(R.id.refresh_complete_item).setVisible(selectedFeed.isPaged());
+ if (StringUtils.isBlank(selectedFeed.getLink())) {
+ menu.findItem(R.id.visit_website_item).setVisible(false);
+ menu.findItem(R.id.share_link_item).setVisible(false);
+ }
return true;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
index 6392d0535..767f71bb6 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -32,6 +32,9 @@ public class PreferenceUpgrader {
}
private static void upgrade(int oldVersion) {
+ if (oldVersion == -1) {
+ return;
+ }
if (oldVersion < 1070196) {
// migrate episode cleanup value (unit changed from days to hours)
int oldValueInDays = UserPreferences.getEpisodeCleanupValue();
diff --git a/app/src/main/res/xml/preferences_playback.xml b/app/src/main/res/xml/preferences_playback.xml
index d609d3daa..2334e1b1c 100644
--- a/app/src/main/res/xml/preferences_playback.xml
+++ b/app/src/main/res/xml/preferences_playback.xml
@@ -76,6 +76,11 @@
android:key="prefPlaybackTimeRespectsSpeed"
android:summary="@string/pref_playback_time_respects_speed_sum"
android:title="@string/pref_playback_time_respects_speed_title"/>
+ <SwitchPreference
+ android:defaultValue="false"
+ android:key="prefStreamOverDownload"
+ android:summary="@string/pref_stream_over_download_sum"
+ android:title="@string/pref_stream_over_download_title"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/queue_label">
diff --git a/app/src/main/res/xml/preferences_user_interface.xml b/app/src/main/res/xml/preferences_user_interface.xml
index c48e9adc8..3402f4ffa 100644
--- a/app/src/main/res/xml/preferences_user_interface.xml
+++ b/app/src/main/res/xml/preferences_user_interface.xml
@@ -32,6 +32,13 @@
android:summary="@string/pref_nav_drawer_feed_counter_sum"
android:defaultValue="0"
app:useStockLayout="true"/>
+ <SwitchPreference
+ android:title="@string/pref_episode_cover_title"
+ android:key="prefEpisodeCover"
+ android:summary="@string/pref_episode_cover_summary"
+ android:defaultValue="true"
+ android:enabled="true"
+ app:useStockLayout="true"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/external_elements">
<SwitchPreference
diff --git a/build.gradle b/build.gradle
index d8e1a6c32..8ac4eda94 100644
--- a/build.gradle
+++ b/build.gradle
@@ -91,4 +91,5 @@ task checkstyle(type: Checkstyle) {
classpath = files()
source "${project.rootDir}"
exclude("**/gen/**")
+ exclude("**/generated/**")
}
diff --git a/config/checkstyle/checkstyle-best-practice.xml b/config/checkstyle/checkstyle-best-practice.xml
index 47586a2bc..3abe4b5e5 100644
--- a/config/checkstyle/checkstyle-best-practice.xml
+++ b/config/checkstyle/checkstyle-best-practice.xml
@@ -187,11 +187,6 @@
</module>
<module name="OverloadMethodsDeclarationOrder"/>
<module name="VariableDeclarationUsageDistance"/>
- <module name="CustomImportOrder">
- <property name="sortImportsInGroupAlphabetically" value="true"/>
- <property name="separateLineBetweenGroups" value="true"/>
- <property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
- </module>
<module name="MethodParamPad"/>
<module name="WhitespaceAfter"/>
<module name="NoWhitespaceBefore">
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 0a5b47eb8..4f916ec3f 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -11,6 +11,13 @@
<module name="TreeWalker">
<module name="OuterTypeFilename"/>
+ <module name="IllegalTokenText">
+ <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
+ <property name="format"
+ value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
+ <property name="message"
+ value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
+ </module>
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/>
@@ -25,6 +32,7 @@
value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<module name="OneStatementPerLine"/>
+ <module name="MultipleVariableDeclarations"/>
<module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
@@ -68,6 +76,11 @@
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
+ <module name="NoWhitespaceBefore">
+ <property name="tokens"
+ value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
+ <property name="allowLineBreaks" value="true"/>
+ </module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationMostCases"/>
<property name="tokens"
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
index 9acd7728a..f549940b7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
@@ -30,7 +30,8 @@ public class DownloaderUpdate {
DownloaderUpdate(@NonNull List<Downloader> downloaders) {
this.downloaders = downloaders;
- LongList feedIds1 = new LongList(), mediaIds1 = new LongList();
+ LongList feedIds1 = new LongList();
+ LongList mediaIds1 = new LongList();
for(Downloader d1 : downloaders) {
int type = d1.getDownloadRequest().getFeedfileType();
long id = d1.getDownloadRequest().getFeedfileId();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/util/ImageResourceUtils.java b/core/src/main/java/de/danoeh/antennapod/core/feed/util/ImageResourceUtils.java
new file mode 100644
index 000000000..674663a6d
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/util/ImageResourceUtils.java
@@ -0,0 +1,45 @@
+package de.danoeh.antennapod.core.feed.util;
+
+import de.danoeh.antennapod.core.asynctask.ImageResource;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
+/**
+ * Utility class to use the appropriate image resource based on {@link UserPreferences}
+ */
+public final class ImageResourceUtils {
+
+ private ImageResourceUtils() {
+ }
+
+ public static String getImageLocation(ImageResource resource) {
+ if (UserPreferences.getUseEpisodeCoverSetting()) {
+ return resource.getImageLocation();
+ } else {
+ return getShowImageLocation(resource);
+ }
+ }
+
+ private static String getShowImageLocation(ImageResource resource) {
+
+ if (resource instanceof FeedItem) {
+ FeedItem item = (FeedItem) resource;
+ if (item.getFeed() != null) {
+ return item.getFeed().getImageLocation();
+ } else {
+ return null;
+ }
+ } else if (resource instanceof FeedMedia) {
+ FeedMedia media = (FeedMedia) resource;
+ FeedItem item = media.getItem();
+ if (item != null && item.getFeed() != null) {
+ return item.getFeed().getImageLocation();
+ } else {
+ return null;
+ }
+ } else {
+ return resource.getImageLocation();
+ }
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackSpeedHelper.java b/core/src/main/java/de/danoeh/antennapod/core/feed/util/PlaybackSpeedUtils.java
index d48e41c3b..0d5ecbb71 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackSpeedHelper.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/util/PlaybackSpeedUtils.java
@@ -1,14 +1,22 @@
-package de.danoeh.antennapod.core.preferences;
+package de.danoeh.antennapod.core.feed.util;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.playback.Playable;
import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
-public class PlaybackSpeedHelper {
+/**
+ * Utility class to use the appropriate playback speed based on {@link PlaybackPreferences}
+ */
+public final class PlaybackSpeedUtils {
+
+ private PlaybackSpeedUtils() {
+ }
/**
* Returns the currently configured playback speed for the specified media.
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
index cbd22ceb0..3cc906b7f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
@@ -83,7 +83,16 @@ public class FastBlurTransformation extends BitmapTransformation {
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
- int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
+ int rsum;
+ int gsum;
+ int bsum;
+ int x;
+ int y;
+ int i;
+ int p;
+ int yp;
+ int yi;
+ int yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
@@ -101,8 +110,12 @@ public class FastBlurTransformation extends BitmapTransformation {
int[] sir;
int rbs;
int r1 = radius + 1;
- int routsum, goutsum, boutsum;
- int rinsum, ginsum, binsum;
+ int routsum;
+ int goutsum;
+ int boutsum;
+ int rinsum;
+ int ginsum;
+ int binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
index ba02a9b8c..be130c00f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
@@ -53,6 +53,7 @@ public class UserPreferences {
private static final String PREF_DRAWER_FEED_ORDER = "prefDrawerFeedOrder";
private static final String PREF_DRAWER_FEED_COUNTER = "prefDrawerFeedIndicator";
public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify";
+ public static final String PREF_USE_EPISODE_COVER = "prefEpisodeCover";
private static final String PREF_PERSISTENT_NOTIFICATION = "prefPersistNotify";
public static final String PREF_COMPACT_NOTIFICATION_BUTTONS = "prefCompactNotificationButtons";
public static final String PREF_LOCKSCREEN_BACKGROUND = "prefLockscreenBackground";
@@ -81,6 +82,7 @@ public class UserPreferences {
private static final String PREF_RESUME_AFTER_CALL = "prefResumeAfterCall";
public static final String PREF_VIDEO_BEHAVIOR = "prefVideoBehavior";
private static final String PREF_TIME_RESPECTS_SPEED = "prefPlaybackTimeRespectsSpeed";
+ private static final String PREF_STREAM_OVER_DOWNLOAD = "prefStreamOverDownload";
// Network
private static final String PREF_ENQUEUE_DOWNLOADED = "prefEnqueueDownloaded";
@@ -232,6 +234,13 @@ public class UserPreferences {
}
/**
+ * @return {@code true} if episodes should use their own cover, {@code false} otherwise
+ */
+ public static boolean getUseEpisodeCoverSetting() {
+ return prefs.getBoolean(PREF_USE_EPISODE_COVER, true);
+ }
+
+ /**
* Returns notification priority.
*
* @return NotificationCompat.PRIORITY_MAX or NotificationCompat.PRIORITY_DEFAULT
@@ -732,7 +741,8 @@ public class UserPreferences {
}
public static String getMediaPlayer() {
- return prefs.getString(PREF_MEDIA_PLAYER, PREF_MEDIA_PLAYER_EXOPLAYER);
+ String s = prefs.getString(PREF_MEDIA_PLAYER, "blaah");
+ return s;
}
public static boolean useSonic() {
@@ -747,6 +757,14 @@ public class UserPreferences {
prefs.edit().putString(PREF_MEDIA_PLAYER, "sonic").apply();
}
+ public static void enableExoplayer() {
+ prefs.edit().putString(PREF_MEDIA_PLAYER, PREF_MEDIA_PLAYER_EXOPLAYER).apply();
+ }
+
+ public static void enableBuiltin() {
+ prefs.edit().putString(PREF_MEDIA_PLAYER, "builtin").apply();
+ }
+
public static boolean stereoToMono() {
return prefs.getBoolean(PREF_STEREO_TO_MONO, false);
}
@@ -931,6 +949,10 @@ public class UserPreferences {
return prefs.getBoolean(PREF_TIME_RESPECTS_SPEED, false);
}
+ public static boolean streamOverDownload() {
+ return prefs.getBoolean(PREF_STREAM_OVER_DOWNLOAD, false);
+ }
+
/**
* Returns if the queue is in keep sorted mode.
*
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
index a34a1e2c3..4f0e84311 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java
@@ -24,12 +24,13 @@ import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.core.receiver.PlayerWidget;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.TimeSpeedConverter;
import de.danoeh.antennapod.core.util.playback.Playable;
@@ -128,7 +129,7 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
int iconSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
icon = Glide.with(PlayerWidgetJobService.this)
.asBitmap()
- .load(media.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(media))
.apply(RequestOptions.diskCacheStrategyOf(ApGlideSettings.AP_DISK_CACHE_STRATEGY))
.submit(iconSize, iconSize)
.get(500, TimeUnit.MILLISECONDS);
@@ -147,7 +148,7 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
progressString = getProgressString(playbackService.getCurrentPosition(),
playbackService.getDuration(), playbackService.getCurrentPlaybackSpeed());
} else {
- progressString = getProgressString(media.getPosition(), media.getDuration(), PlaybackSpeedHelper.getCurrentPlaybackSpeed(media));
+ progressString = getProgressString(media.getPosition(), media.getDuration(), PlaybackSpeedUtils.getCurrentPlaybackSpeed(media));
}
if (progressString != null) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
index 1584d29d2..485349cb1 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
@@ -27,7 +27,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import de.danoeh.antennapod.core.feed.MediaType;
-import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
import de.danoeh.antennapod.core.util.playback.AudioPlayer;
@@ -243,7 +243,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
try {
media.loadMetadata();
callback.onMediaChanged(false);
- setPlaybackParams(PlaybackSpeedHelper.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence());
+ setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence());
if (stream) {
mediaPlayer.setDataSource(media.getStreamUrl());
} else if (media.getLocalMediaUrl() != null && new File(media.getLocalMediaUrl()).canRead()) {
@@ -307,7 +307,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
Log.d(TAG, "Resuming/Starting playback");
acquireWifiLockIfNecessary();
- setPlaybackParams(PlaybackSpeedHelper.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence());
+ setPlaybackParams(PlaybackSpeedUtils.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence());
setVolume(UserPreferences.getLeftVolume(), UserPreferences.getRightVolume());
if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index 5002fb913..a37e73357 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -67,6 +67,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.FeedSearcher;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.QueueAccess;
@@ -1138,7 +1139,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, p.getFeedTitle());
- String imageLocation = p.getImageLocation();
+ String imageLocation = ImageResourceUtils.getImageLocation(p);
if (!TextUtils.isEmpty(imageLocation)) {
if (UserPreferences.setLockscreenBackground()) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
index b277a6bc2..be9a02445 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
@@ -24,6 +24,7 @@ import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.IntList;
import de.danoeh.antennapod.core.util.TimeSpeedConverter;
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
@@ -76,7 +77,7 @@ public class PlaybackServiceNotificationBuilder {
try {
icon = Glide.with(context)
.asBitmap()
- .load(playable.getImageLocation())
+ .load(ImageResourceUtils.getImageLocation(playable))
.apply(RequestOptions.diskCacheStrategyOf(ApGlideSettings.AP_DISK_CACHE_STRATEGY))
.apply(new RequestOptions().centerCrop())
.submit(iconSize, iconSize)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
index a8206d3bd..8d77f0f24 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.core.util;
+import org.apache.commons.lang3.StringUtils;
+
import java.util.List;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -45,9 +47,9 @@ public class FeedItemUtil {
public static String getLinkWithFallback(FeedItem item) {
if (item == null) {
return null;
- } else if (item.getLink() != null) {
+ } else if (StringUtils.isNotBlank(item.getLink())) {
return item.getLink();
- } else if (item.getFeed() != null) {
+ } else if (StringUtils.isNotBlank(item.getFeed().getLink())) {
return item.getFeed().getLink();
}
return null;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java
index 7290b9d98..8589e1283 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/id3reader/ID3Reader.java
@@ -206,7 +206,8 @@ public class ID3Reader {
private int readUnicodeString(StringBuilder strBuffer, InputStream input, int max, Charset charset)
throws IOException, ID3ReaderException {
byte[] buffer = new byte[max];
- int c, cZero = -1;
+ int c;
+ int cZero = -1;
int i = 0;
for (; i < max; i++) {
c = input.read();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index ba903eeb9..beb0a202d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -29,7 +29,7 @@ import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper;
+import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
@@ -705,7 +705,7 @@ public class PlaybackController {
if (playbackService != null && canSetPlaybackSpeed()) {
return playbackService.getCurrentPlaybackSpeed();
} else {
- return PlaybackSpeedHelper.getCurrentPlaybackSpeed(getMedia());
+ return PlaybackSpeedUtils.getCurrentPlaybackSpeed(getMedia());
}
}
diff --git a/core/src/main/res/drawable/borderless_button_dark.xml b/core/src/main/res/drawable/borderless_button_dark.xml
index 6d263938d..3a44d81a2 100644
--- a/core/src/main/res/drawable/borderless_button_dark.xml
+++ b/core/src/main/res/drawable/borderless_button_dark.xml
@@ -1,13 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"><shape android:shape="rectangle">
+ <item android:state_pressed="true">
+ <shape android:shape="rectangle">
<solid android:color="@color/selection_background_color_dark" />
- </shape></item>
- <item android:state_focused="true"><shape android:shape="rectangle">
+ </shape>
+ </item>
+ <item android:state_focused="true">
+ <shape android:shape="rectangle">
<solid android:color="@color/selection_background_color_dark" />
- </shape></item>
- <item><shape android:shape="rectangle">
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
<solid android:color="@android:color/transparent" />
- </shape></item>
-
+ </shape>
+ </item>
</selector> \ No newline at end of file
diff --git a/core/src/main/res/values-v19/colors.xml b/core/src/main/res/values-v16/colors.xml
index 4154280e8..4154280e8 100644
--- a/core/src/main/res/values-v19/colors.xml
+++ b/core/src/main/res/values-v16/colors.xml
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 5a0267232..def43fe8a 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -376,6 +376,8 @@
<string name="pref_pauseOnHeadsetDisconnect_title">Headphones Disconnect</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Headphones Reconnect</string>
<string name="pref_unpauseOnBluetoothReconnect_title">Bluetooth Reconnect</string>
+ <string name="pref_stream_over_download_title">Prefer Streaming</string>
+ <string name="pref_stream_over_download_sum">Display stream button instead of download button in lists.</string>
<string name="pref_mobileUpdate_title">Mobile Updates</string>
<string name="pref_mobileUpdate_sum">Select what should be allowed over the mobile data connection</string>
<string name="pref_mobileUpdate_refresh">Feed refresh</string>
@@ -403,6 +405,8 @@
<string name="pref_parallel_downloads_title">Parallel Downloads</string>
<string name="pref_episode_cache_title">Episode Cache</string>
<string name="pref_episode_cache_summary">Total number of downloaded episodes cached on the device. Automatic download will be suspended if this number is reached.</string>
+ <string name="pref_episode_cover_title">Use Episode Cover</string>
+ <string name="pref_episode_cover_summary">Use the episode specific cover whenever available. If unchecked, the app will always use the podcast cover image.</string>
<string name="pref_theme_title_use_system">Use system theme</string>
<string name="pref_theme_title_light">Light</string>
<string name="pref_theme_title_dark">Dark</string>
diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java
new file mode 100644
index 000000000..0b64cb10f
--- /dev/null
+++ b/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemUtilTest.java
@@ -0,0 +1,73 @@
+package de.danoeh.antennapod.core.util;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+
+import static org.junit.Assert.assertEquals;
+
+public class FeedItemUtilTest {
+
+
+ @RunWith(Parameterized.class)
+ public static class LinkWithFallbackTest {
+ private static final String FEED_LINK = "http://example.com";
+ private static final String ITEM_LINK = "http://example.com/feedItem1";
+
+ @Parameters
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ { "average",
+ FEED_LINK, ITEM_LINK, ITEM_LINK },
+ { "null item link - fallback to feed",
+ FEED_LINK, null, FEED_LINK},
+ { "empty item link - same as null",
+ FEED_LINK, "", FEED_LINK},
+ { "blank item link - same as null",
+ FEED_LINK, " ", FEED_LINK},
+ { "fallback, but feed link is null too",
+ null, null, null },
+ { "fallback - but empty feed link - same as null",
+ "", null, null},
+ { "fallback - but blank feed link - same as null",
+ " ", null, null}
+ });
+ }
+
+ private final String msg;
+ private final String feedLink;
+ private final String itemLink;
+ private final String expected;
+
+ public LinkWithFallbackTest(String msg, String feedLink, String itemLink, String expected) {
+ this.msg = msg;
+ this.feedLink = feedLink;
+ this.itemLink = itemLink;
+ this.expected = expected;
+ }
+
+
+ @Test
+ public void testLinkWithFallback() {
+ String actual = FeedItemUtil.getLinkWithFallback(createFeedItem(feedLink, itemLink));
+ assertEquals(msg, expected, actual);
+ }
+
+ private static FeedItem createFeedItem(String feedLink, String itemLink) {
+ Feed feed = new Feed();
+ feed.setLink(feedLink);
+ FeedItem feedItem = new FeedItem();
+ feedItem.setLink(itemLink);
+ feedItem.setFeed(feed);
+ feed.setItems(Arrays.asList(feedItem));
+ return feedItem;
+ }
+ }
+}