Merge pull request #3471 from orionlee/bugfix2_player_not_using_downloaded_media_2947

New fix player stuck due to streaming rather than using downloaded media
This commit is contained in:
H. Lehmann 2019-09-30 21:34:17 +02:00 committed by GitHub
commit f862d15753
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 115 additions and 8 deletions

View File

@ -5,23 +5,31 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.LargeTest;
import org.awaitility.Awaitility;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
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.service.playback.PlaybackServiceTaskManager;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.playback.Playable;
import org.greenrobot.eventbus.EventBus;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import io.reactivex.functions.Consumer;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@ -123,6 +131,72 @@ public class PlaybackServiceTaskManagerTest {
pstm.shutdown();
}
@Test
public void testQueueUpdatedUponDownloadComplete() throws Exception {
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();
{ // Setup test data
List<FeedItem> queue = writeTestQueue("a");
FeedItem item = DBReader.getFeedItem(queue.get(0).getId());
FeedMedia media = new FeedMedia(item, "http://example.com/episode.mp3", 12345, "audio/mp3");
item.setMedia(media);
DBWriter.setFeedMedia(media).get();
DBWriter.setFeedItem(item).get();
}
PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM);
final FeedItem testItem = pstm.getQueue().get(0);
assertFalse("The item should not yet be downloaded", testItem.getMedia().isDownloaded());
withFeedItemEventListener( feedItemEventListener -> {
// simulate download complete (in DownloadService.MediaHandlerThread)
FeedItem item = DBReader.getFeedItem(testItem.getId());
item.getMedia().setDownloaded(true);
item.getMedia().setFile_url("file://123");
item.setAutoDownload(false);
DBWriter.setFeedMedia(item.getMedia()).get();
DBWriter.setFeedItem(item).get();
Awaitility.await()
.atMost(1000, TimeUnit.MILLISECONDS)
.until(() -> feedItemEventListener.getEvents().size() > 0);
final FeedItem itemUpdated = pstm.getQueue().get(0);
assertTrue("media.isDownloaded() should be true - The queue in PlaybackService should be updated after download is completed",
itemUpdated.getMedia().isDownloaded());
});
pstm.shutdown();
}
/**
* Provides an listener subscribing to {@link FeedItemEvent} that the callers can use
*
* Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown.
*/
private static void withFeedItemEventListener(Consumer<FeedItemEventListener> consumer) throws Exception {
FeedItemEventListener feedItemEventListener = new FeedItemEventListener();
try {
EventBus.getDefault().register(feedItemEventListener);
consumer.accept(feedItemEventListener);
} finally {
EventBus.getDefault().unregister(feedItemEventListener);
}
}
private static class FeedItemEventListener {
private final List<FeedItemEvent> events = new ArrayList<>();
@Subscribe
public void onEvent(FeedItemEvent event) {
events.add(event);
}
List<? extends FeedItemEvent> getEvents() {
return events;
}
}
@Test
public void testStartPositionSaver() throws InterruptedException {
final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext();

View File

@ -997,14 +997,17 @@ public class DownloadService extends Service {
final FeedItem item = media.getItem();
try {
DBWriter.setFeedMedia(media).get();
// we've received the media, we don't want to autodownload it again
if (item != null) {
item.setAutoDownload(false);
// setFeedItem() signals (via EventBus) that the item has been updated,
// so we do it after the enclosing media has been updated above,
// to ensure subscribers will get the updated FeedMedia as well
DBWriter.setFeedItem(item).get();
}
DBWriter.setFeedMedia(media).get();
if (item != null && UserPreferences.enqueueDownloadedEpisodes() &&
!DBTasks.isInQueue(DownloadService.this, item.getId())) {
DBWriter.addQueueItem(DownloadService.this, item).get();

View File

@ -7,6 +7,9 @@ import android.os.Vibrator;
import android.support.annotation.NonNull;
import android.util.Log;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@ -14,13 +17,12 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.playback.Playable;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import io.reactivex.Completable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@ -102,6 +104,34 @@ public class PlaybackServiceTaskManager {
}
}
@Subscribe
public void onEvent(FeedItemEvent event) {
// Use case: when an item in the queue has been downloaded,
// listening to the event to ensure the downloaded item will be used.
Log.d(TAG, "onEvent(FeedItemEvent " + event + ")");
for (FeedItem item : event.items) {
if (isItemInQueue(item.getId())) {
Log.d(TAG, "onEvent(FeedItemEvent) - some item (" + item.getId() + ") in the queue has been updated (usually downloaded). Refresh the queue.");
cancelQueueLoader();
loadQueue();
return;
}
}
}
private boolean isItemInQueue(long itemId) {
List<FeedItem> queue = getQueueIfLoaded();
if (queue != null) {
for (FeedItem item : queue) {
if (item.getId() == itemId) {
return true;
}
}
}
return false;
}
/**
* Returns the queue if it is already loaded or null if it hasn't been loaded yet.
* In order to wait until the queue has been loaded, use getQueue()