diff options
Diffstat (limited to 'app')
10 files changed, 138 insertions, 59 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java index 3b5b35946..d0e14d70a 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java @@ -5,7 +5,6 @@ import androidx.annotation.Nullable; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; -import de.danoeh.antennapod.core.service.download.DownloaderFactory; import org.awaitility.Awaitility; import org.awaitility.core.ConditionTimeoutException; import org.junit.After; @@ -22,10 +21,12 @@ import java.util.concurrent.TimeUnit; 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.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadRequest; import de.danoeh.antennapod.core.service.download.DownloadService; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.service.download.Downloader; +import de.danoeh.antennapod.core.service.download.DownloaderFactory; import de.danoeh.antennapod.core.service.download.StubDownloader; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; @@ -58,7 +59,9 @@ public class DownloadServiceTest { } private Feed setUpTestFeeds() throws Exception { - Feed feed = new Feed("url", null, "Test Feed title 1"); + // To avoid complication in case of test failures, leaving behind orphaned + // media files: add a timestamp so that each test run will have its own directory for media files. + Feed feed = new Feed("url", null, "Test Feed title 1 " + System.currentTimeMillis()); List<FeedItem> items = new ArrayList<>(); feed.setItems(items); FeedItem item1 = new FeedItem(0, "Item 1-1", "Item 1-1", "url", new Date(), FeedItem.NEW, feed); @@ -77,29 +80,108 @@ public class DownloadServiceTest { } @Test - public void testEventsGeneratedCaseMediaDownloadSuccess() throws Exception { + public void testEventsGeneratedCaseMediaDownloadSuccess_noEnqueue() throws Exception { + doTestEventsGeneratedCaseMediaDownloadSuccess(false, 1); + } + + @Test + public void testEventsGeneratedCaseMediaDownloadSuccess_withEnqueue() throws Exception { + // enqueue itself generates additional FeedItem event + doTestEventsGeneratedCaseMediaDownloadSuccess(true, 2); + } + + private void doTestEventsGeneratedCaseMediaDownloadSuccess(boolean enqueueDownloaded, + int numEventsExpected) + throws Exception { // create a stub download that returns successful // // OPEN: Ideally, I'd like the download time long enough so that multiple in-progress DownloadEvents // are generated (to simulate typical download), but it'll make download time quite long (1-2 seconds) // to do so DownloadService.setDownloaderFactory(new StubDownloaderFactory(50, downloadStatus -> { - downloadStatus.setSuccessful(); + downloadStatus.setSuccessful(); })); + UserPreferences.setEnqueueDownloadedEpisodes(enqueueDownloaded); withFeedItemEventListener(feedItemEventListener -> { try { assertEquals(0, feedItemEventListener.getEvents().size()); assertFalse("The media in test should not yet been downloaded", DBReader.getFeedMedia(testMedia11.getId()).isDownloaded()); - DownloadRequester.getInstance().downloadMedia(InstrumentationRegistry.getTargetContext(), - testMedia11); - Awaitility.await() + DownloadRequester.getInstance().downloadMedia(false, InstrumentationRegistry.getTargetContext(), + testMedia11.getItem());Awaitility.await() .atMost(1000, TimeUnit.MILLISECONDS) - .until(() -> feedItemEventListener.getEvents().size() > 0); + .until(() -> feedItemEventListener.getEvents().size() >= numEventsExpected); assertTrue("After media download has completed, FeedMedia object in db should indicate so.", DBReader.getFeedMedia(testMedia11.getId()).isDownloaded()); + assertEquals("The FeedItem should have been " + (enqueueDownloaded ? "" : "not ") + "enqueued", + enqueueDownloaded, + DBReader.getQueueIDList().contains(testMedia11.getItem().getId())); + } catch (ConditionTimeoutException cte) { + fail("The expected FeedItemEvent (for media download complete) has not been posted. " + + cte.getMessage()); + } + }); + } + + @Test + public void testCancelDownload_UndoEnqueue_Normal() throws Exception { + doTestCancelDownload_UndoEnqueue(false); + } + + @Test + public void testCancelDownload_UndoEnqueue_AlreadyInQueue() throws Exception { + doTestCancelDownload_UndoEnqueue(true); + } + + private void doTestCancelDownload_UndoEnqueue(boolean itemAlreadyInQueue) throws Exception { + // let download takes longer to ensure the test can cancel the download in time + DownloadService.setDownloaderFactory(new StubDownloaderFactory(150, downloadStatus -> { + downloadStatus.setSuccessful(); + })); + UserPreferences.setEnqueueDownloadedEpisodes(true); + UserPreferences.setEnableAutodownload(false); + + final long item1Id = testMedia11.getItem().getId(); + if (itemAlreadyInQueue) { + // simulate item already in queue condition + DBWriter.addQueueItem(InstrumentationRegistry.getTargetContext(), false, item1Id).get(); + assertTrue(DBReader.getQueueIDList().contains(item1Id)); + } else { + assertFalse(DBReader.getQueueIDList().contains(item1Id)); + } + + withFeedItemEventListener(feedItemEventListener -> { + try { + DownloadRequester.getInstance().downloadMedia(false, InstrumentationRegistry.getTargetContext(), + testMedia11.getItem()); + if (itemAlreadyInQueue) { + Awaitility.await("download service receives the request - " + + "no event is expected before cancel is issued") + .atLeast(100, TimeUnit.MILLISECONDS) + .until(() -> true); + } else { + Awaitility.await("item enqueue event") + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() -> feedItemEventListener.getEvents().size() >= 1); + } + DownloadRequester.getInstance().cancelDownload(InstrumentationRegistry.getTargetContext(), + testMedia11); + final int totalNumEventsExpected = itemAlreadyInQueue ? 1 : 3; + Awaitility.await("item dequeue event + download termination event") + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() ->feedItemEventListener.getEvents().size() >= totalNumEventsExpected); + assertFalse("The download should have been canceled", + DBReader.getFeedMedia(testMedia11.getId()).isDownloaded()); + if (itemAlreadyInQueue) { + assertTrue("The FeedItem should still be in the queue after the download is cancelled." + + " It's there before download.", + DBReader.getQueueIDList().contains(item1Id)); + } else { + assertFalse("The FeedItem should not be in the queue after the download is cancelled.", + DBReader.getQueueIDList().contains(item1Id)); + } } catch (ConditionTimeoutException cte) { fail("The expected FeedItemEvent (for media download complete) has not been posted. " + cte.getMessage()); diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java index cce4e5111..090cd2213 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java @@ -206,7 +206,7 @@ public class DBTasksTest { // Run actual test and assert results List<? extends FeedItem> actualEnqueued = - DBTasks.enqueueFeedItemsToDownload(context, itemsToDownload); + DBTasks.enqueueFeedItemsToDownload(context, Arrays.asList(itemsToDownload)); assertEqualsByIds("Only items not in the queue are enqueued", expectedEnqueued, actualEnqueued); assertEqualsByIds("Queue has new items appended", expectedQueue, DBReader.getQueue()); @@ -229,7 +229,7 @@ public class DBTasksTest { // Run actual test and assert results List<? extends FeedItem> actualEnqueued = - DBTasks.enqueueFeedItemsToDownload(context, itemsToDownload); + DBTasks.enqueueFeedItemsToDownload(context, Arrays.asList(itemsToDownload)); assertEqualsByIds("No item is enqueued", expectedEnqueued, actualEnqueued); assertEqualsByIds("Queue is unchanged", expectedQueue, DBReader.getQueue()); 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 fd669f3e6..ed1698ecf 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -54,7 +54,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR private final boolean showOnlyNewEpisodes; private FeedItem selectedItem; - private Holder currentlyPlayingItem = null; private final int playingBackGroundColor; private final int normalBackGroundColor; @@ -172,7 +171,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR if (media.isCurrentlyPlaying()) { holder.container.setBackgroundColor(playingBackGroundColor); - currentlyPlayingItem = holder; } else { holder.container.setBackgroundColor(normalBackGroundColor); } @@ -202,22 +200,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR .load(); } - @Override - public void onBindViewHolder(@NonNull Holder holder, int pos, List<Object> payload) { - onBindViewHolder(holder, pos); - - if (holder == currentlyPlayingItem && payload.size() == 1 && payload.get(0) instanceof PlaybackPositionEvent) { - PlaybackPositionEvent event = (PlaybackPositionEvent) payload.get(0); - holder.progress.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); - } - } - - public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event) { - if (currentlyPlayingItem != null && currentlyPlayingItem.getAdapterPosition() != RecyclerView.NO_POSITION) { - notifyItemChanged(currentlyPlayingItem.getAdapterPosition(), event); - } - } - @Nullable public FeedItem getSelectedItem() { return selectedItem; @@ -302,6 +284,14 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item); } + public boolean isCurrentlyPlayingItem() { + return item.getMedia() != null && item.getMedia().isCurrentlyPlaying(); + } + + public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) { + progress.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + } + } public interface ItemAccess { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java index b8764c2ae..4d66fd486 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java @@ -2,7 +2,6 @@ package de.danoeh.antennapod.adapter; import android.content.Context; import android.os.Build; -import androidx.core.content.ContextCompat; import android.text.Layout; import android.text.format.DateUtils; import android.util.Log; @@ -13,6 +12,8 @@ import android.widget.BaseAdapter; import android.widget.TextView; import android.widget.Toast; +import androidx.core.content.ContextCompat; + import com.joanzapata.iconify.widget.IconButton; import com.joanzapata.iconify.widget.IconTextView; @@ -24,6 +25,7 @@ import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DownloadRequestException; +import de.danoeh.antennapod.core.storage.DownloadRequester; /** Displays a list of DownloadStatus entries. */ public class DownloadLogAdapter extends BaseAdapter { @@ -132,7 +134,7 @@ public class DownloadLogAdapter extends BaseAdapter { FeedMedia media = DBReader.getFeedMedia(holder.id); if (media != null) { try { - DBTasks.downloadFeedItems(context, media.getItem()); + DownloadRequester.getInstance().downloadMedia(context, media.getItem()); Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show(); } catch (DownloadRequestException e) { e.printStackTrace(); 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 42f009c85..ddfcfe0d3 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java @@ -61,7 +61,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap private boolean locked; private FeedItem selectedItem; - private ViewHolder currentlyPlayingItem = null; private final int playingBackGroundColor; private final int normalBackGroundColor; @@ -84,11 +83,13 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap notifyDataSetChanged(); } + @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.queue_listitem, parent, false); return new ViewHolder(view); } + @Override public void onBindViewHolder(ViewHolder holder, int pos) { FeedItem item = itemAccess.getItem(pos); holder.bind(item); @@ -98,18 +99,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap }); } - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int pos, List<Object> payload) { - onBindViewHolder(holder, pos); - - if (holder == currentlyPlayingItem && payload.size() == 1 && payload.get(0) instanceof PlaybackPositionEvent) { - PlaybackPositionEvent event = (PlaybackPositionEvent) payload.get(0); - holder.progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); - holder.progressLeft.setText(Converter.getDurationStringLong(event.getPosition())); - holder.progressRight.setText(Converter.getDurationStringLong(event.getDuration())); - } - } - @Nullable public FeedItem getSelectedItem() { return selectedItem; @@ -125,12 +114,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap return itemAccess.getCount(); } - public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event) { - if (currentlyPlayingItem != null && currentlyPlayingItem.getAdapterPosition() != RecyclerView.NO_POSITION) { - notifyItemChanged(currentlyPlayingItem.getAdapterPosition(), event); - } - } - public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnCreateContextMenuListener, @@ -310,7 +293,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap if(media.isCurrentlyPlaying()) { container.setBackgroundColor(playingBackGroundColor); - currentlyPlayingItem = this; } else { container.setBackgroundColor(normalBackGroundColor); } @@ -330,6 +312,15 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap .load(); } + public boolean isCurrentlyPlayingItem() { + return item.getMedia() != null && item.getMedia().isCurrentlyPlaying(); + } + + public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) { + progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + progressLeft.setText(Converter.getDurationStringLong(event.getPosition())); + progressRight.setText(Converter.getDurationStringLong(event.getDuration())); + } } public interface ItemAccess { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java index 55ca5471b..026386cf9 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java @@ -1,16 +1,16 @@ package de.danoeh.antennapod.adapter.actionbutton; import android.content.Context; +import android.widget.Toast; + import androidx.annotation.AttrRes; import androidx.annotation.NonNull; import androidx.annotation.StringRes; -import android.widget.Toast; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; 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.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; @@ -64,7 +64,7 @@ class DownloadActionButton extends ItemActionButton { private void downloadEpisode(Context context) { try { - DBTasks.downloadFeedItems(context, item); + DownloadRequester.getInstance().downloadMedia(context, item); Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show(); } catch (DownloadRequestException e) { e.printStackTrace(); diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java index 4fdfe231d..77efd9023 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MobileDownloadHelper.java @@ -8,9 +8,9 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.core.feed.FeedItem; 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.DownloadRequestException; +import de.danoeh.antennapod.core.storage.DownloadRequester; class MobileDownloadHelper { private static long addToQueueTimestamp; @@ -48,7 +48,7 @@ class MobileDownloadHelper { private static void downloadFeedItems(Context context, FeedItem item) { allowMobileDownloadTimestamp = System.currentTimeMillis(); try { - DBTasks.downloadFeedItems(context, item); + DownloadRequester.getInstance().downloadMedia(context, item); Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show(); } catch (DownloadRequestException e) { e.printStackTrace(); diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index 447e98dac..ff131aeba 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -36,9 +36,9 @@ import java.util.Map; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; +import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.FeedItemPermutors; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.SortOrder; @@ -485,7 +485,7 @@ public class EpisodesApplyActionFragment extends Fragment { } } try { - DBTasks.downloadFeedItems(getActivity(), toDownload.toArray(new FeedItem[toDownload.size()])); + DownloadRequester.getInstance().downloadMedia(getActivity(), toDownload.toArray(new FeedItem[toDownload.size()])); } catch (DownloadRequestException e) { e.printStackTrace(); DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage()); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index 3802e1f65..fe48de815 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -383,7 +383,14 @@ public abstract class EpisodesListFragment extends Fragment { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(PlaybackPositionEvent event) { if (listAdapter != null) { - listAdapter.notifyCurrentlyPlayingItemChanged(event); + for (int i = 0; i < listAdapter.getItemCount(); i++) { + AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) + recyclerView.findViewHolderForAdapterPosition(i); + if (holder != null && holder.isCurrentlyPlayingItem()) { + holder.notifyPlaybackPositionUpdated(event); + break; + } + } } } 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 ce1276175..82b388b1b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -212,7 +212,14 @@ public class QueueFragment extends Fragment { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(PlaybackPositionEvent event) { if (recyclerAdapter != null) { - recyclerAdapter.notifyCurrentlyPlayingItemChanged(event); + for (int i = 0; i < recyclerAdapter.getItemCount(); i++) { + QueueRecyclerAdapter.ViewHolder holder = (QueueRecyclerAdapter.ViewHolder) + recyclerView.findViewHolderForAdapterPosition(i); + if (holder != null && holder.isCurrentlyPlayingItem()) { + holder.notifyPlaybackPositionUpdated(event); + break; + } + } } } |