enqueue location: use the new 3-value settings
This commit is contained in:
parent
52521ecddb
commit
bddd2bfa2e
@ -189,7 +189,7 @@ public class DBTasksTest {
|
|||||||
public void testAddQueueItemsInDownload_EnqueueEnabled() throws Exception {
|
public void testAddQueueItemsInDownload_EnqueueEnabled() throws Exception {
|
||||||
// Setup test data / environment
|
// Setup test data / environment
|
||||||
UserPreferences.setEnqueueDownloadedEpisodes(true);
|
UserPreferences.setEnqueueDownloadedEpisodes(true);
|
||||||
UserPreferences.setEnqueueAtFront(false);
|
UserPreferences.setEnqueueLocation(UserPreferences.EnqueueLocation.BACK);
|
||||||
|
|
||||||
List<FeedItem> fis1 = createSavedFeed("Feed 1", 2).getItems();
|
List<FeedItem> fis1 = createSavedFeed("Feed 1", 2).getItems();
|
||||||
List<FeedItem> fis2 = createSavedFeed("Feed 2", 3).getItems();
|
List<FeedItem> fis2 = createSavedFeed("Feed 2", 3).getItems();
|
||||||
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
import androidx.test.rule.ActivityTestRule;
|
import androidx.test.rule.ActivityTestRule;
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.activity.PreferenceActivity;
|
import de.danoeh.antennapod.activity.PreferenceActivity;
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
|
import de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation;
|
||||||
import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
|
import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
|
||||||
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
|
import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm;
|
||||||
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
|
import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm;
|
||||||
@ -129,7 +131,17 @@ public class PreferencesTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testEnqueueLocation() {
|
public void testEnqueueLocation() {
|
||||||
clickPreference(R.string.playback_pref);
|
clickPreference(R.string.playback_pref);
|
||||||
// TODO-2652: implement the test
|
doTestEnqueueLocation(R.string.enqueue_location_after_current, EnqueueLocation.AFTER_CURRENTLY_PLAYING);
|
||||||
|
doTestEnqueueLocation(R.string.enqueue_location_front, EnqueueLocation.FRONT);
|
||||||
|
doTestEnqueueLocation(R.string.enqueue_location_back, EnqueueLocation.BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestEnqueueLocation(@StringRes int optionResId, EnqueueLocation expected) {
|
||||||
|
clickPreference(R.string.pref_enqueue_location_title);
|
||||||
|
onView(withText(optionResId)).perform(click());
|
||||||
|
assertTrue(solo.waitForCondition(
|
||||||
|
() -> expected == UserPreferences.getEnqueueLocation(),
|
||||||
|
Timeout.getLargeTimeout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -7,6 +7,7 @@ import android.preference.PreferenceManager;
|
|||||||
import de.danoeh.antennapod.BuildConfig;
|
import de.danoeh.antennapod.BuildConfig;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
|
import de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation;
|
||||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||||
|
|
||||||
@ -75,6 +76,13 @@ public class PreferenceUpgrader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UserPreferences.setQueueLocked(false);
|
UserPreferences.setQueueLocked(false);
|
||||||
|
|
||||||
|
if (!prefs.contains(UserPreferences.PREF_ENQUEUE_LOCATION)) {
|
||||||
|
final String keyOldPrefEnqueueFront = "prefQueueAddToFront";
|
||||||
|
boolean enqueueAtFront = prefs.getBoolean(keyOldPrefEnqueueFront, false);
|
||||||
|
EnqueueLocation enqueueLocation = enqueueAtFront ? EnqueueLocation.FRONT : EnqueueLocation.BACK;
|
||||||
|
UserPreferences.setEnqueueLocation(enqueueLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,9 +63,6 @@ public class UserPreferences {
|
|||||||
public static final String PREF_BACK_BUTTON_BEHAVIOR = "prefBackButtonBehavior";
|
public static final String PREF_BACK_BUTTON_BEHAVIOR = "prefBackButtonBehavior";
|
||||||
private static final String PREF_BACK_BUTTON_GO_TO_PAGE = "prefBackButtonGoToPage";
|
private static final String PREF_BACK_BUTTON_GO_TO_PAGE = "prefBackButtonGoToPage";
|
||||||
|
|
||||||
// Queue
|
|
||||||
public static final String PREF_QUEUE_ADD_TO_FRONT = "prefQueueAddToFront";
|
|
||||||
public static final String PREF_QUEUE_KEEP_IN_PROGESS_AT_FRONT = "prefQueueKeepInProgressAtFront";
|
|
||||||
public static final String PREF_QUEUE_KEEP_SORTED = "prefQueueKeepSorted";
|
public static final String PREF_QUEUE_KEEP_SORTED = "prefQueueKeepSorted";
|
||||||
public static final String PREF_QUEUE_KEEP_SORTED_ORDER = "prefQueueKeepSortedOrder";
|
public static final String PREF_QUEUE_KEEP_SORTED_ORDER = "prefQueueKeepSortedOrder";
|
||||||
|
|
||||||
@ -299,6 +296,7 @@ public class UserPreferences {
|
|||||||
BACK, FRONT, AFTER_CURRENTLY_PLAYING;
|
BACK, FRONT, AFTER_CURRENTLY_PLAYING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public static EnqueueLocation getEnqueueLocation() {
|
public static EnqueueLocation getEnqueueLocation() {
|
||||||
String valStr = prefs.getString(PREF_ENQUEUE_LOCATION, EnqueueLocation.BACK.name());
|
String valStr = prefs.getString(PREF_ENQUEUE_LOCATION, EnqueueLocation.BACK.name());
|
||||||
try {
|
try {
|
||||||
@ -310,29 +308,12 @@ public class UserPreferences {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO-2652: migrate settings
|
public static void setEnqueueLocation(@NonNull EnqueueLocation location) {
|
||||||
|
|
||||||
public static boolean enqueueAtFront() { // TODO-2652: migrate to the new settings
|
|
||||||
return prefs.getBoolean(PREF_QUEUE_ADD_TO_FRONT, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public static void setEnqueueAtFront(boolean enqueueAtFront) { // TODO-2652: migrate to the new settings
|
|
||||||
prefs.edit()
|
prefs.edit()
|
||||||
.putBoolean(PREF_QUEUE_ADD_TO_FRONT, enqueueAtFront)
|
.putString(PREF_ENQUEUE_LOCATION, location.name())
|
||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return {@code true} if in enqueuing items/podcast episodes, when the existing front item is
|
|
||||||
* in-progress, i.e., the user has played part of it, such item remains at the front of the
|
|
||||||
* queue; {@code false} otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean keepInProgressAtFront() { // TODO-2652: migrate to the new settings
|
|
||||||
return prefs.getBoolean(PREF_QUEUE_KEEP_IN_PROGESS_AT_FRONT, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPauseOnHeadsetDisconnect() {
|
public static boolean isPauseOnHeadsetDisconnect() {
|
||||||
return prefs.getBoolean(PREF_PAUSE_ON_HEADSET_DISCONNECT, true);
|
return prefs.getBoolean(PREF_PAUSE_ON_HEADSET_DISCONNECT, true);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import de.danoeh.antennapod.core.util.IntentUtils;
|
|||||||
import de.danoeh.antennapod.core.util.LongList;
|
import de.danoeh.antennapod.core.util.LongList;
|
||||||
import de.danoeh.antennapod.core.util.Permutor;
|
import de.danoeh.antennapod.core.util.Permutor;
|
||||||
import de.danoeh.antennapod.core.util.SortOrder;
|
import de.danoeh.antennapod.core.util.SortOrder;
|
||||||
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides methods for writing data to AntennaPod's database.
|
* Provides methods for writing data to AntennaPod's database.
|
||||||
@ -326,19 +327,15 @@ public class DBWriter {
|
|||||||
List<QueueEvent> events = new ArrayList<>();
|
List<QueueEvent> events = new ArrayList<>();
|
||||||
List<FeedItem> updatedItems = new ArrayList<>();
|
List<FeedItem> updatedItems = new ArrayList<>();
|
||||||
ItemEnqueuePositionCalculator positionCalculator =
|
ItemEnqueuePositionCalculator positionCalculator =
|
||||||
new ItemEnqueuePositionCalculator(
|
new ItemEnqueuePositionCalculator(UserPreferences.getEnqueueLocation());
|
||||||
new ItemEnqueuePositionCalculator.Options()
|
Playable currentlyPlaying = Playable.PlayableUtils.createInstanceFromPreferences(context);
|
||||||
.setEnqueueAtFront(UserPreferences.enqueueAtFront())
|
|
||||||
.setKeepInProgressAtFront(UserPreferences.keepInProgressAtFront())
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < itemIds.length; i++) {
|
for (int i = 0; i < itemIds.length; i++) {
|
||||||
if (!itemListContains(queue, itemIds[i])) {
|
if (!itemListContains(queue, itemIds[i])) {
|
||||||
final FeedItem item = DBReader.getFeedItem(itemIds[i]);
|
final FeedItem item = DBReader.getFeedItem(itemIds[i]);
|
||||||
|
|
||||||
|
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
int insertPosition = positionCalculator.calcPosition(i, item, queue);
|
int insertPosition = positionCalculator.calcPosition(i, item, queue, currentlyPlaying);
|
||||||
queue.add(insertPosition, item);
|
queue.add(insertPosition, item);
|
||||||
events.add(QueueEvent.added(item, insertPosition));
|
events.add(QueueEvent.added(item, insertPosition));
|
||||||
|
|
||||||
|
@ -3,11 +3,15 @@ package de.danoeh.antennapod.core.storage;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||||
|
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||||
|
import de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation;
|
||||||
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see DBWriter#addQueueItem(Context, boolean, long...) it uses the class to determine
|
* @see DBWriter#addQueueItem(Context, boolean, long...) it uses the class to determine
|
||||||
@ -15,65 +19,41 @@ import de.danoeh.antennapod.core.feed.FeedItem;
|
|||||||
*/
|
*/
|
||||||
class ItemEnqueuePositionCalculator {
|
class ItemEnqueuePositionCalculator {
|
||||||
|
|
||||||
public static class Options {
|
|
||||||
private boolean enqueueAtFront = false;
|
|
||||||
private boolean keepInProgressAtFront = false;
|
|
||||||
|
|
||||||
public boolean isEnqueueAtFront() {
|
|
||||||
return enqueueAtFront;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Options setEnqueueAtFront(boolean enqueueAtFront) {
|
|
||||||
this.enqueueAtFront = enqueueAtFront;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isKeepInProgressAtFront() {
|
|
||||||
return keepInProgressAtFront;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Options setKeepInProgressAtFront(boolean keepInProgressAtFront) {
|
|
||||||
this.keepInProgressAtFront = keepInProgressAtFront;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Options options;
|
private final EnqueueLocation enqueueLocation;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
DownloadStateProvider downloadStateProvider = DownloadRequester.getInstance();
|
DownloadStateProvider downloadStateProvider = DownloadRequester.getInstance();
|
||||||
|
|
||||||
public ItemEnqueuePositionCalculator(@NonNull Options options) {
|
public ItemEnqueuePositionCalculator(@NonNull EnqueueLocation enqueueLocation) {
|
||||||
this.options = options;
|
this.enqueueLocation = enqueueLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @param positionAmongToAdd Typically, the callers has a list of items to be inserted to
|
* @param positionAmongToAdd Typically, the callers has a list of items to be inserted to
|
||||||
* the queue. This parameter indicates the position (0-based) of
|
* the queue. This parameter indicates the position (0-based) of
|
||||||
* the item among the one to inserted. E.g., it is needed for
|
* the item among the one to inserted. E.g., it is needed for
|
||||||
* enqueue at front option.
|
* enqueue at front option.
|
||||||
*
|
* @param item the item to be inserted
|
||||||
* @param item the item to be inserted
|
* @param curQueue the queue to which the item is to be inserted
|
||||||
* @param curQueue the queue to which the item is to be inserted
|
* @param currentPlaying the currently playing media
|
||||||
* @return the position (0-based) the item should be inserted to the named queu
|
* @return the position (0-based) the item should be inserted to the named queue
|
||||||
*/
|
*/
|
||||||
public int calcPosition(int positionAmongToAdd, FeedItem item, List<FeedItem> curQueue) {
|
public int calcPosition(int positionAmongToAdd, @NonNull FeedItem item,
|
||||||
if (options.isEnqueueAtFront()) {
|
@NonNull List<FeedItem> curQueue, @Nullable Playable currentPlaying) {
|
||||||
if (options.isKeepInProgressAtFront() &&
|
switch (enqueueLocation) {
|
||||||
curQueue.size() > 0 &&
|
case BACK:
|
||||||
curQueue.get(0).getMedia() != null &&
|
return curQueue.size();
|
||||||
curQueue.get(0).getMedia().isInProgress()) {
|
case FRONT:
|
||||||
// leave the front in progress item at the front
|
|
||||||
return getPositionOfFirstNonDownloadingItem(positionAmongToAdd + 1, curQueue);
|
|
||||||
} else { // typical case
|
|
||||||
// return NOT 0, so that when a list of items are inserted, the items inserted
|
// return NOT 0, so that when a list of items are inserted, the items inserted
|
||||||
// keep the same order. Returning 0 will reverse the order
|
// keep the same order. Returning 0 will reverse the order
|
||||||
return getPositionOfFirstNonDownloadingItem(positionAmongToAdd, curQueue);
|
return getPositionOfFirstNonDownloadingItem(positionAmongToAdd, curQueue);
|
||||||
}
|
case AFTER_CURRENTLY_PLAYING:
|
||||||
} else {
|
int currentlyPlayingPosition = getCurrentlyPlayingPosition(curQueue, currentPlaying);
|
||||||
return curQueue.size();
|
return getPositionOfFirstNonDownloadingItem(
|
||||||
|
currentlyPlayingPosition + (1 + positionAmongToAdd), curQueue);
|
||||||
|
default:
|
||||||
|
throw new AssertionError("calcPosition() : unrecognized enqueueLocation option: " + enqueueLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,4 +83,18 @@ class ItemEnqueuePositionCalculator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getCurrentlyPlayingPosition(@NonNull List<FeedItem> curQueue,
|
||||||
|
@Nullable Playable currentPlaying) {
|
||||||
|
if (!(currentPlaying instanceof FeedMedia)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
final long curPlayingItemId = ((FeedMedia) currentPlaying).getItem().getId();
|
||||||
|
for (int i = 0; i < curQueue.size(); i++) {
|
||||||
|
if (curPlayingItemId == curQueue.get(i).getId()) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,10 +455,10 @@
|
|||||||
<string name="pref_showDownloadReport_sum">If downloads fail, generate a report that shows the details of the failure.</string>
|
<string name="pref_showDownloadReport_sum">If downloads fail, generate a report that shows the details of the failure.</string>
|
||||||
<string name="pref_expand_notify_unsupport_toast">Android versions before 4.1 do not support expanded notifications.</string>
|
<string name="pref_expand_notify_unsupport_toast">Android versions before 4.1 do not support expanded notifications.</string>
|
||||||
<string name="pref_enqueue_location_title">Enqueue Location</string>
|
<string name="pref_enqueue_location_title">Enqueue Location</string>
|
||||||
<string name="pref_enqueue_location_sum">Add episodes to: %1$s.</string>
|
<string name="pref_enqueue_location_sum">Add episodes to: %1$s</string>
|
||||||
<string name="enqueue_location_back">back of the queue</string>
|
<string name="enqueue_location_back">Back</string>
|
||||||
<string name="enqueue_location_front">front of the queue</string>
|
<string name="enqueue_location_front">Front</string>
|
||||||
<string name="enqueue_location_after_current">after current episode</string>
|
<string name="enqueue_location_after_current">After current episode</string>
|
||||||
<string name="pref_smart_mark_as_played_disabled">Disabled</string>
|
<string name="pref_smart_mark_as_played_disabled">Disabled</string>
|
||||||
<string name="pref_image_cache_size_title">Image Cache Size</string>
|
<string name="pref_image_cache_size_title">Image Cache Size</string>
|
||||||
<string name="pref_image_cache_size_sum">Size of the disk cache for images.</string>
|
<string name="pref_image_cache_size_sum">Size of the disk cache for images.</string>
|
||||||
|
@ -16,9 +16,16 @@ import java.util.stream.Collectors;
|
|||||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.core.feed.FeedMother;
|
import de.danoeh.antennapod.core.feed.FeedMother;
|
||||||
import de.danoeh.antennapod.core.storage.ItemEnqueuePositionCalculator.Options;
|
import de.danoeh.antennapod.core.feed.MediaType;
|
||||||
import de.danoeh.antennapod.core.util.CollectionTestUtil;
|
import de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation;
|
||||||
|
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
|
||||||
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
|
|
||||||
|
import static de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation.AFTER_CURRENTLY_PLAYING;
|
||||||
|
import static de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation.BACK;
|
||||||
|
import static de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation.FRONT;
|
||||||
|
import static de.danoeh.antennapod.core.util.CollectionTestUtil.concat;
|
||||||
|
import static de.danoeh.antennapod.core.util.CollectionTestUtil.list;
|
||||||
import static de.danoeh.antennapod.core.util.FeedItemUtil.getIdList;
|
import static de.danoeh.antennapod.core.util.FeedItemUtil.getIdList;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
@ -31,28 +38,25 @@ public class ItemEnqueuePositionCalculatorTest {
|
|||||||
public static class BasicTest {
|
public static class BasicTest {
|
||||||
@Parameters(name = "{index}: case<{0}>, expected:{1}")
|
@Parameters(name = "{index}: case<{0}>, expected:{1}")
|
||||||
public static Iterable<Object[]> data() {
|
public static Iterable<Object[]> data() {
|
||||||
Options optDefault = new Options();
|
|
||||||
Options optEnqAtFront = new Options().setEnqueueAtFront(true);
|
|
||||||
|
|
||||||
return Arrays.asList(new Object[][]{
|
return Arrays.asList(new Object[][]{
|
||||||
{"case default, i.e., add to the end",
|
{"case default, i.e., add to the end",
|
||||||
CollectionTestUtil.concat(QUEUE_DEFAULT_IDS, TFI_ID),
|
concat(QUEUE_DEFAULT_IDS, TFI_ID),
|
||||||
optDefault, 0, QUEUE_DEFAULT},
|
BACK, 0, QUEUE_DEFAULT},
|
||||||
{"case default (2nd item)",
|
{"case default (2nd item)",
|
||||||
CollectionTestUtil.concat(QUEUE_DEFAULT_IDS, TFI_ID),
|
concat(QUEUE_DEFAULT_IDS, TFI_ID),
|
||||||
optDefault, 1, QUEUE_DEFAULT},
|
BACK, 1, QUEUE_DEFAULT},
|
||||||
{"case option enqueue at front",
|
{"case option enqueue at front",
|
||||||
CollectionTestUtil.concat(TFI_ID, QUEUE_DEFAULT_IDS),
|
concat(TFI_ID, QUEUE_DEFAULT_IDS),
|
||||||
optEnqAtFront, 0, QUEUE_DEFAULT},
|
FRONT, 0, QUEUE_DEFAULT},
|
||||||
{"case option enqueue at front (2nd item)",
|
{"case option enqueue at front (2nd item)",
|
||||||
CollectionTestUtil.list(11L, TFI_ID, 12L, 13L, 14L),
|
list(11L, TFI_ID, 12L, 13L, 14L),
|
||||||
optEnqAtFront, 1, QUEUE_DEFAULT},
|
FRONT, 1, QUEUE_DEFAULT},
|
||||||
{"case empty queue, option default",
|
{"case empty queue, option default",
|
||||||
CollectionTestUtil.list(TFI_ID),
|
list(TFI_ID),
|
||||||
optDefault, 0, QUEUE_EMPTY},
|
BACK, 0, QUEUE_EMPTY},
|
||||||
{"case empty queue, option enqueue at front",
|
{"case empty queue, option enqueue at front",
|
||||||
CollectionTestUtil.list(TFI_ID),
|
list(TFI_ID),
|
||||||
optEnqAtFront, 0, QUEUE_EMPTY},
|
FRONT, 0, QUEUE_EMPTY},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +67,7 @@ public class ItemEnqueuePositionCalculatorTest {
|
|||||||
public List<Long> idsExpected;
|
public List<Long> idsExpected;
|
||||||
|
|
||||||
@Parameter(2)
|
@Parameter(2)
|
||||||
public Options options;
|
public EnqueueLocation options;
|
||||||
|
|
||||||
@Parameter(3)
|
@Parameter(3)
|
||||||
public int posAmongAdded; // the position of feed item to be inserted among the list to be inserted.
|
public int posAmongAdded; // the position of feed item to be inserted among the list to be inserted.
|
||||||
@ -71,7 +75,6 @@ public class ItemEnqueuePositionCalculatorTest {
|
|||||||
@Parameter(4)
|
@Parameter(4)
|
||||||
public List<FeedItem> curQueue;
|
public List<FeedItem> curQueue;
|
||||||
|
|
||||||
|
|
||||||
public static final long TFI_ID = 101;
|
public static final long TFI_ID = 101;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,49 +88,62 @@ public class ItemEnqueuePositionCalculatorTest {
|
|||||||
List<FeedItem> queue = new ArrayList<>(curQueue);
|
List<FeedItem> queue = new ArrayList<>(curQueue);
|
||||||
FeedItem tFI = tFI(TFI_ID);
|
FeedItem tFI = tFI(TFI_ID);
|
||||||
doAddToQueueAndAssertResult(message,
|
doAddToQueueAndAssertResult(message,
|
||||||
calculator, posAmongAdded, tFI, queue,
|
calculator, posAmongAdded, tFI, queue, getCurrentlyPlaying(),
|
||||||
idsExpected);
|
idsExpected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Playable getCurrentlyPlaying() { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@RunWith(Parameterized.class)
|
@RunWith(Parameterized.class)
|
||||||
public static class KeepInProgressAtFrontTest extends BasicTest {
|
public static class AfterCurrentlyPlayingTest extends BasicTest {
|
||||||
@Parameters(name = "{index}: case<{0}>, expected:{1}")
|
@Parameters(name = "{index}: case<{0}>, expected:{1}")
|
||||||
public static Iterable<Object[]> data() {
|
public static Iterable<Object[]> data() {
|
||||||
Options optKeepInProgressAtFront =
|
|
||||||
new Options().setEnqueueAtFront(true).setKeepInProgressAtFront(true);
|
|
||||||
// edge case: keep in progress without enabling enqueue at front is meaningless
|
|
||||||
Options optKeepInProgressAtFrontWithNoEnqueueAtFront =
|
|
||||||
new Options().setKeepInProgressAtFront(true);
|
|
||||||
|
|
||||||
return Arrays.asList(new Object[][]{
|
return Arrays.asList(new Object[][]{
|
||||||
{"case option keep in progress at front",
|
{"case option after currently playing",
|
||||||
CollectionTestUtil.list(11L, TFI_ID, 12L, 13L),
|
list(11L, TFI_ID, 12L, 13L, 14L),
|
||||||
optKeepInProgressAtFront, 0, QUEUE_FRONT_IN_PROGRESS},
|
AFTER_CURRENTLY_PLAYING, 0, QUEUE_DEFAULT, 11L},
|
||||||
{"case option keep in progress at front (2nd item)",
|
{"case option after currently playing (2nd item)",
|
||||||
CollectionTestUtil.list(11L, 12L, TFI_ID, 13L),
|
list(11L, 12L, TFI_ID, 13L, 14L),
|
||||||
optKeepInProgressAtFront, 1, QUEUE_FRONT_IN_PROGRESS},
|
AFTER_CURRENTLY_PLAYING, 1, QUEUE_DEFAULT, 11L},
|
||||||
{"case option keep in progress at front, front item not in progress",
|
{"case option after currently playing, currently playing in the middle of the queue",
|
||||||
CollectionTestUtil.concat(TFI_ID, QUEUE_DEFAULT_IDS),
|
list(11L, 12L, 13L, TFI_ID, 14L),
|
||||||
optKeepInProgressAtFront, 0, QUEUE_DEFAULT},
|
AFTER_CURRENTLY_PLAYING, 0, QUEUE_DEFAULT, 13L},
|
||||||
{"case option keep in progress at front, front item no media at all",
|
{"case option after currently playing, currently playing is not in queue",
|
||||||
CollectionTestUtil.concat(TFI_ID, QUEUE_FRONT_NO_MEDIA_IDS),
|
concat(TFI_ID, QUEUE_DEFAULT_IDS),
|
||||||
optKeepInProgressAtFront, 0, QUEUE_FRONT_NO_MEDIA}, // No media should not cause any exception
|
AFTER_CURRENTLY_PLAYING, 0, QUEUE_DEFAULT, 99L},
|
||||||
{"case option keep in progress at front, but enqueue at front is disabled",
|
{"case option after currently playing, no currentlyPlaying is null",
|
||||||
CollectionTestUtil.concat(QUEUE_FRONT_IN_PROGRESS_IDS, TFI_ID),
|
concat(TFI_ID, QUEUE_DEFAULT_IDS),
|
||||||
optKeepInProgressAtFrontWithNoEnqueueAtFront, 0, QUEUE_FRONT_IN_PROGRESS},
|
AFTER_CURRENTLY_PLAYING, 0, QUEUE_DEFAULT, ID_CURRENTLY_PLAYING_NULL},
|
||||||
{"case empty queue, option keep in progress at front",
|
{"case option after currently playing, currentlyPlaying is externalMedia",
|
||||||
CollectionTestUtil.list(TFI_ID),
|
concat(TFI_ID, QUEUE_DEFAULT_IDS),
|
||||||
optKeepInProgressAtFront, 0, QUEUE_EMPTY},
|
AFTER_CURRENTLY_PLAYING, 0, QUEUE_DEFAULT, ID_CURRENTLY_PLAYING_NOT_FEEDMEDIA},
|
||||||
|
{"case empty queue, option after currently playing",
|
||||||
|
list(TFI_ID),
|
||||||
|
AFTER_CURRENTLY_PLAYING, 0, QUEUE_EMPTY, ID_CURRENTLY_PLAYING_NULL},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final List<FeedItem> QUEUE_FRONT_IN_PROGRESS = Arrays.asList(tFI(11, 60000), tFI(12), tFI(13));
|
@Parameter(5)
|
||||||
private static final List<Long> QUEUE_FRONT_IN_PROGRESS_IDS = getIdList(QUEUE_FRONT_IN_PROGRESS);
|
public long idCurrentlyPlaying = -1;
|
||||||
|
|
||||||
private static final List<FeedItem> QUEUE_FRONT_NO_MEDIA = Arrays.asList(tFINoMedia(11), tFI(12), tFI(13));
|
@Override
|
||||||
private static final List<Long> QUEUE_FRONT_NO_MEDIA_IDS = getIdList(QUEUE_FRONT_NO_MEDIA);
|
Playable getCurrentlyPlaying() {
|
||||||
|
if (ID_CURRENTLY_PLAYING_NOT_FEEDMEDIA == idCurrentlyPlaying) {
|
||||||
|
return externalMedia();
|
||||||
|
}
|
||||||
|
if (ID_CURRENTLY_PLAYING_NULL == idCurrentlyPlaying) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tFI(idCurrentlyPlaying).getMedia();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Playable externalMedia() {
|
||||||
|
return new ExternalMedia("http://example.com/episode.mp3", MediaType.AUDIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long ID_CURRENTLY_PLAYING_NULL = -1L;
|
||||||
|
private static final long ID_CURRENTLY_PLAYING_NOT_FEEDMEDIA = -9999L;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,24 +152,21 @@ public class ItemEnqueuePositionCalculatorTest {
|
|||||||
|
|
||||||
@Parameters(name = "{index}: case<{0}>")
|
@Parameters(name = "{index}: case<{0}>")
|
||||||
public static Iterable<Object[]> data() {
|
public static Iterable<Object[]> data() {
|
||||||
Options optDefault = new Options();
|
|
||||||
Options optEnqAtFront = new Options().setEnqueueAtFront(true);
|
|
||||||
|
|
||||||
// Attempts to make test more readable by showing the expected list of ids
|
// Attempts to make test more readable by showing the expected list of ids
|
||||||
// (rather than the expected positions)
|
// (rather than the expected positions)
|
||||||
return Arrays.asList(new Object[][] {
|
return Arrays.asList(new Object[][] {
|
||||||
{"download order test, enqueue default",
|
{"download order test, enqueue default",
|
||||||
CollectionTestUtil.concat(QUEUE_DEFAULT_IDS, 101L),
|
concat(QUEUE_DEFAULT_IDS, 101L),
|
||||||
CollectionTestUtil.concat(QUEUE_DEFAULT_IDS, CollectionTestUtil.list(101L, 102L)),
|
concat(QUEUE_DEFAULT_IDS, list(101L, 102L)),
|
||||||
CollectionTestUtil.concat(QUEUE_DEFAULT_IDS, CollectionTestUtil.list(101L, 102L, 201L)),
|
concat(QUEUE_DEFAULT_IDS, list(101L, 102L, 201L)),
|
||||||
CollectionTestUtil.concat(QUEUE_DEFAULT_IDS, CollectionTestUtil.list(101L, 102L, 201L, 202L)),
|
concat(QUEUE_DEFAULT_IDS, list(101L, 102L, 201L, 202L)),
|
||||||
optDefault, QUEUE_DEFAULT},
|
BACK, QUEUE_DEFAULT},
|
||||||
{"download order test, enqueue at front",
|
{"download order test, enqueue at front",
|
||||||
CollectionTestUtil.concat(101L, QUEUE_DEFAULT_IDS),
|
concat(101L, QUEUE_DEFAULT_IDS),
|
||||||
CollectionTestUtil.concat(CollectionTestUtil.list(101L, 102L), QUEUE_DEFAULT_IDS),
|
concat(list(101L, 102L), QUEUE_DEFAULT_IDS),
|
||||||
CollectionTestUtil.concat(CollectionTestUtil.list(101L, 102L, 201L), QUEUE_DEFAULT_IDS),
|
concat(list(101L, 102L, 201L), QUEUE_DEFAULT_IDS),
|
||||||
CollectionTestUtil.concat(CollectionTestUtil.list(101L, 102L, 201L, 202L), QUEUE_DEFAULT_IDS),
|
concat(list(101L, 102L, 201L, 202L), QUEUE_DEFAULT_IDS),
|
||||||
optEnqAtFront, QUEUE_DEFAULT},
|
FRONT, QUEUE_DEFAULT},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +187,7 @@ public class ItemEnqueuePositionCalculatorTest {
|
|||||||
public List<Long> idsExpectedAfter202;
|
public List<Long> idsExpectedAfter202;
|
||||||
|
|
||||||
@Parameter(5)
|
@Parameter(5)
|
||||||
public Options options;
|
public EnqueueLocation options;
|
||||||
|
|
||||||
@Parameter(6)
|
@Parameter(6)
|
||||||
public List<FeedItem> queueInitial;
|
public List<FeedItem> queueInitial;
|
||||||
@ -217,7 +230,7 @@ public class ItemEnqueuePositionCalculatorTest {
|
|||||||
|
|
||||||
FeedItem tFI202 = tFI_isDownloading(202, stubDownloadStateProvider);
|
FeedItem tFI202 = tFI_isDownloading(202, stubDownloadStateProvider);
|
||||||
doAddToQueueAndAssertResult(message + " (bulk insertion, 2nd item)",
|
doAddToQueueAndAssertResult(message + " (bulk insertion, 2nd item)",
|
||||||
calculator, 1, tFI202, queue,
|
calculator, 1, tFI202, queue, null,
|
||||||
idsExpectedAfter202);
|
idsExpectedAfter202);
|
||||||
|
|
||||||
// TODO: simulate download failure cases.
|
// TODO: simulate download failure cases.
|
||||||
@ -249,31 +262,34 @@ public class ItemEnqueuePositionCalculatorTest {
|
|||||||
FeedItem itemToAdd,
|
FeedItem itemToAdd,
|
||||||
List<FeedItem> queue,
|
List<FeedItem> queue,
|
||||||
List<Long> idsExpected) {
|
List<Long> idsExpected) {
|
||||||
int posActual = calculator.calcPosition(positionAmongAdd, itemToAdd, queue);
|
doAddToQueueAndAssertResult(message, calculator, positionAmongAdd, itemToAdd, queue, null, idsExpected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doAddToQueueAndAssertResult(String message,
|
||||||
|
ItemEnqueuePositionCalculator calculator,
|
||||||
|
int positionAmongAdd,
|
||||||
|
FeedItem itemToAdd,
|
||||||
|
List<FeedItem> queue,
|
||||||
|
Playable currentlyPlaying,
|
||||||
|
List<Long> idsExpected) {
|
||||||
|
int posActual = calculator.calcPosition(positionAmongAdd, itemToAdd, queue, currentlyPlaying);
|
||||||
queue.add(posActual, itemToAdd);
|
queue.add(posActual, itemToAdd);
|
||||||
assertEquals(message, idsExpected, getIdList(queue));
|
assertEquals(message, idsExpected, getIdList(queue));
|
||||||
}
|
}
|
||||||
|
|
||||||
static final List<FeedItem> QUEUE_EMPTY = Collections.unmodifiableList(Arrays.asList());
|
static final List<FeedItem> QUEUE_EMPTY = Collections.unmodifiableList(Arrays.asList());
|
||||||
|
|
||||||
static final List<FeedItem> QUEUE_DEFAULT = Collections.unmodifiableList(Arrays.asList(tFI(11), tFI(12), tFI(13), tFI(14)));
|
static final List<FeedItem> QUEUE_DEFAULT =
|
||||||
static final List<Long> QUEUE_DEFAULT_IDS = QUEUE_DEFAULT.stream().map(fi -> fi.getId()).collect(Collectors.toList());
|
Collections.unmodifiableList(Arrays.asList(tFI(11), tFI(12), tFI(13), tFI(14)));
|
||||||
|
static final List<Long> QUEUE_DEFAULT_IDS =
|
||||||
|
QUEUE_DEFAULT.stream().map(fi -> fi.getId()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
||||||
static FeedItem tFI(long id) {
|
static FeedItem tFI(long id) {
|
||||||
return tFI(id, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FeedItem tFI(long id, int position) {
|
|
||||||
FeedItem item = tFINoMedia(id);
|
FeedItem item = tFINoMedia(id);
|
||||||
FeedMedia media = new FeedMedia(item, "download_url", 1234567, "audio/mpeg");
|
FeedMedia media = new FeedMedia(item, "download_url", 1234567, "audio/mpeg");
|
||||||
media.setId(item.getId());
|
media.setId(item.getId());
|
||||||
item.setMedia(media);
|
item.setMedia(media);
|
||||||
|
|
||||||
if (position >= 0) {
|
|
||||||
media.setPosition(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user