diff options
Diffstat (limited to 'core')
9 files changed, 86 insertions, 90 deletions
diff --git a/core/build.gradle b/core/build.gradle index 32899cb5d..700487701 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -39,10 +39,10 @@ dependencies { implementation 'androidx.documentfile:documentfile:1.0.1' implementation "androidx.fragment:fragment:$fragmentVersion" implementation "androidx.media:media:$mediaVersion" + implementation "androidx.palette:palette:$paletteVersion" implementation "androidx.preference:preference:$preferenceVersion" implementation "androidx.work:work-runtime:$workManagerVersion" implementation "com.google.android.material:material:$googleMaterialVersion" - implementation 'androidx.palette:palette:1.0.0' implementation "org.apache.commons:commons-lang3:$commonslangVersion" implementation "commons-io:commons-io:$commonsioVersion" @@ -69,9 +69,9 @@ dependencies { testImplementation 'androidx.test:core:1.2.0' testImplementation "org.awaitility:awaitility:$awaitilityVersion" - testImplementation 'junit:junit:4.13' + testImplementation "junit:junit:$junitVersion" testImplementation 'org.mockito:mockito-inline:3.5.13' - testImplementation 'org.robolectric:robolectric:4.5-alpha-1' + testImplementation "org.robolectric:robolectric:$robolectricVersion" testImplementation 'javax.inject:javax.inject:1' androidTestImplementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion" androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java index 9bc273c9e..29de6ca80 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java @@ -117,10 +117,17 @@ public class FavoritesWriter implements ExportWriter { } private void writeFavoriteItem(Writer writer, FeedItem item, String favoriteTemplate) throws IOException { - String favItem = favoriteTemplate - .replace("{FAV_TITLE}", item.getTitle().trim()) - .replace("{FAV_WEBSITE}", item.getLink()) - .replace("{FAV_MEDIA}", item.getMedia().getDownload_url()); + String favItem = favoriteTemplate.replace("{FAV_TITLE}", item.getTitle().trim()); + if (item.getLink() != null) { + favItem = favItem.replace("{FAV_WEBSITE}", item.getLink()); + } else { + favItem = favItem.replace("{FAV_WEBSITE}", ""); + } + if (item.getMedia() != null && item.getMedia().getDownload_url() != null) { + favItem = favItem.replace("{FAV_MEDIA}", item.getMedia().getDownload_url()); + } else { + favItem = favItem.replace("{FAV_MEDIA}", ""); + } writer.append(favItem); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ResizingOkHttpStreamFetcher.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ResizingOkHttpStreamFetcher.java index 11e2f944e..1871723bb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/ResizingOkHttpStreamFetcher.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ResizingOkHttpStreamFetcher.java @@ -3,12 +3,13 @@ package de.danoeh.antennapod.core.glide; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Build; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.bumptech.glide.Priority; import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher; import com.bumptech.glide.load.model.GlideUrl; -import com.google.android.exoplayer2.util.Log; import okhttp3.Call; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; @@ -22,7 +23,7 @@ import java.io.InputStream; import java.io.OutputStream; public class ResizingOkHttpStreamFetcher extends OkHttpStreamFetcher { - private static final String TAG = "ResizingOkHttpStreamFetcher"; + private static final String TAG = "ResizingOkHttpStreamFet"; private static final int MAX_DIMENSIONS = 1500; private static final int MAX_FILE_SIZE = 1024 * 1024; // 1 MB diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java index 7ce06a9fb..d4008b3f2 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ExoPlayerWrapper.java @@ -12,20 +12,21 @@ import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.audio.AudioAttributes; -import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory; +import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.ProgressiveMediaSource; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.ExoTrackSelection; import com.google.android.exoplayer2.trackselection.MappingTrackSelector; -import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.ui.DefaultTrackNameProvider; import com.google.android.exoplayer2.ui.TrackNameProvider; @@ -48,6 +49,7 @@ import org.antennapod.audio.MediaPlayer; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; @@ -88,12 +90,12 @@ public class ExoPlayerWrapper implements IPlayer { trackSelector = new DefaultTrackSelector(context); exoPlayer = new SimpleExoPlayer.Builder(context, new DefaultRenderersFactory(context)) .setTrackSelector(trackSelector) - .setLoadControl(loadControl.createDefaultLoadControl()) + .setLoadControl(loadControl.build()) .build(); exoPlayer.setSeekParameters(SeekParameters.EXACT); - exoPlayer.addListener(new Player.EventListener() { + exoPlayer.addListener(new Player.Listener() { @Override - public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + public void onPlaybackStateChanged(@Player.State int playbackState) { if (audioCompletionListener != null && playbackState == Player.STATE_ENDED) { audioCompletionListener.onCompletion(null); } else if (infoListener != null && playbackState == Player.STATE_BUFFERING) { @@ -119,8 +121,10 @@ public class ExoPlayerWrapper implements IPlayer { } @Override - public void onSeekProcessed() { - if (audioSeekCompleteListener != null) { + public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, + @NonNull Player.PositionInfo newPosition, + @Player.DiscontinuityReason int reason) { + if (audioSeekCompleteListener != null && reason == Player.DISCONTINUITY_REASON_SEEK) { audioSeekCompleteListener.onSeekComplete(null); } } @@ -157,12 +161,13 @@ public class ExoPlayerWrapper implements IPlayer { @Override public void pause() { - exoPlayer.setPlayWhenReady(false); + exoPlayer.pause(); } @Override public void prepare() throws IllegalStateException { - exoPlayer.prepare(mediaSource, false, true); + exoPlayer.setMediaSource(mediaSource, false); + exoPlayer.prepare(); } @Override @@ -198,25 +203,31 @@ public class ExoPlayerWrapper implements IPlayer { b.setContentType(i); b.setFlags(a.flags); b.setUsage(a.usage); - exoPlayer.setAudioAttributes(b.build()); + exoPlayer.setAudioAttributes(b.build(), false); } public void setDataSource(String s, String user, String password) throws IllegalArgumentException, IllegalStateException { Log.d(TAG, "setDataSource: " + s); - OkHttpDataSourceFactory httpDataSourceFactory = new OkHttpDataSourceFactory( - AntennapodHttpClient.getHttpClient(), ClientConfig.USER_AGENT); + final OkHttpDataSource.Factory httpDataSourceFactory = + new OkHttpDataSource.Factory(AntennapodHttpClient.getHttpClient()) + .setUserAgent(ClientConfig.USER_AGENT); if (!TextUtils.isEmpty(user) && !TextUtils.isEmpty(password)) { - httpDataSourceFactory.getDefaultRequestProperties().set("Authorization", - HttpDownloader.encodeCredentials(user, password, "ISO-8859-1")); + final HashMap<String, String> requestProperties = new HashMap<>(); + requestProperties.put( + "Authorization", + HttpDownloader.encodeCredentials(user, password, "ISO-8859-1") + ); + httpDataSourceFactory.setDefaultRequestProperties(requestProperties); } DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, null, httpDataSourceFactory); DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory(); extractorsFactory.setConstantBitrateSeekingEnabled(true); extractorsFactory.setMp3ExtractorFlags(Mp3Extractor.FLAG_DISABLE_ID3_METADATA); ProgressiveMediaSource.Factory f = new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory); - mediaSource = f.createMediaSource(Uri.parse(s)); + final MediaItem mediaItem = MediaItem.fromUri(Uri.parse(s)); + mediaSource = f.createMediaSource(mediaItem); } @Override @@ -231,7 +242,8 @@ public class ExoPlayerWrapper implements IPlayer { @Override public void setPlaybackParams(float speed, boolean skipSilence) { - playbackParameters = new PlaybackParameters(speed, playbackParameters.pitch, skipSilence); + playbackParameters = new PlaybackParameters(speed, playbackParameters.pitch); + exoPlayer.setSkipSilenceEnabled(skipSilence); exoPlayer.setPlaybackParameters(playbackParameters); } @@ -252,7 +264,7 @@ public class ExoPlayerWrapper implements IPlayer { @Override public void start() { - exoPlayer.setPlayWhenReady(true); + exoPlayer.play(); // Can't set params when paused - so always set it on start in case they changed exoPlayer.setPlaybackParameters(playbackParameters); } @@ -312,7 +324,7 @@ public class ExoPlayerWrapper implements IPlayer { TrackSelectionArray trackSelections = exoPlayer.getCurrentTrackSelections(); List<Format> availableFormats = getFormats(); for (int i = 0; i < trackSelections.length; i++) { - TrackSelection track = trackSelections.get(i); + ExoTrackSelection track = (ExoTrackSelection) trackSelections.get(i); if (track == null) { continue; } 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 d5e0140d0..22378e01a 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 @@ -1231,7 +1231,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_SKIP_TO_NEXT - | PlaybackStateCompat.ACTION_SEEK_TO; + | PlaybackStateCompat.ACTION_SEEK_TO + | PlaybackStateCompat.ACTION_SET_PLAYBACK_SPEED; if (useSkipToPreviousForRewindInLockscreen()) { // Workaround to fool Android so that Lockscreen will expose a skip-to-previous button, @@ -1888,6 +1889,12 @@ public class PlaybackService extends MediaBrowserServiceCompat { } @Override + public void onSetPlaybackSpeed(float speed) { + Log.d(TAG, "onSetPlaybackSpeed()"); + setSpeed(speed); + } + + @Override public boolean onMediaButtonEvent(final Intent mediaButton) { Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")"); if (mediaButton != null) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index 0e996c6c8..fdaab745e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -149,7 +149,6 @@ public class DBWriter { */ public static Future<?> deleteFeed(final Context context, final long feedId) { return dbExec.submit(() -> { - DownloadRequester requester = DownloadRequester.getInstance(); final Feed feed = DBReader.getFeed(feedId); if (feed == null) { return; @@ -167,7 +166,9 @@ public class DBWriter { adapter.removeFeed(feed); adapter.close(); - SynchronizationQueueSink.enqueueFeedRemovedIfSynchronizationIsActive(context, feed.getDownload_url()); + if (!feed.isLocalFeed()) { + SynchronizationQueueSink.enqueueFeedRemovedIfSynchronizationIsActive(context, feed.getDownload_url()); + } EventBus.getDefault().post(new FeedListUpdateEvent(feed)); }); } @@ -779,7 +780,9 @@ public class DBWriter { adapter.close(); for (Feed feed : feeds) { - SynchronizationQueueSink.enqueueFeedAddedIfSynchronizationIsActive(context, feed.getDownload_url()); + if (!feed.isLocalFeed()) { + SynchronizationQueueSink.enqueueFeedAddedIfSynchronizationIsActive(context, feed.getDownload_url()); + } } BackupManager backupManager = new BackupManager(context); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 719e546b5..b7e221a33 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -44,8 +44,6 @@ import de.danoeh.antennapod.model.feed.SortOrder; import static de.danoeh.antennapod.model.feed.FeedPreferences.SPEED_USE_GLOBAL; import static de.danoeh.antennapod.model.feed.SortOrder.toCodeString; -// TODO Remove media column from feeditem table - /** * Implements methods for accessing the database */ @@ -842,43 +840,32 @@ public class PodDBAdapter { db.delete(TABLE_NAME_QUEUE, null, null); } - private void removeFeedMedia(FeedMedia media) { - // delete download log entries for feed media - db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_FEEDFILE + "=? AND " + KEY_FEEDFILETYPE + "=?", - new String[]{String.valueOf(media.getId()), String.valueOf(FeedMedia.FEEDFILETYPE_FEEDMEDIA)}); - - db.delete(TABLE_NAME_FEED_MEDIA, KEY_ID + "=?", - new String[]{String.valueOf(media.getId())}); - } - - private void removeChaptersOfItem(FeedItem item) { - db.delete(TABLE_NAME_SIMPLECHAPTERS, KEY_FEEDITEM + "=?", - new String[]{String.valueOf(item.getId())}); - } - - /** - * Remove a FeedItem and its FeedMedia entry. - */ - private void removeFeedItem(FeedItem item) { - if (item.getMedia() != null) { - removeFeedMedia(item.getMedia()); - } - if (item.hasChapters() || item.getChapters() != null) { - removeChaptersOfItem(item); - } - db.delete(TABLE_NAME_FEED_ITEMS, KEY_ID + "=?", - new String[]{String.valueOf(item.getId())}); - } - /** * Remove the listed items and their FeedMedia entries. */ public void removeFeedItems(@NonNull List<FeedItem> items) { try { - db.beginTransactionNonExclusive(); + StringBuilder mediaIds = new StringBuilder(); + StringBuilder itemIds = new StringBuilder(); for (FeedItem item : items) { - removeFeedItem(item); + if (item.getMedia() != null) { + if (mediaIds.length() != 0) { + mediaIds.append(","); + } + mediaIds.append(item.getMedia().getId()); + } + if (itemIds.length() != 0) { + itemIds.append(","); + } + itemIds.append(item.getId()); } + + db.beginTransactionNonExclusive(); + db.delete(TABLE_NAME_SIMPLECHAPTERS, KEY_FEEDITEM + " IN (" + itemIds + ")", null); + db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_FEEDFILETYPE + "=" + FeedMedia.FEEDFILETYPE_FEEDMEDIA + + " AND " + KEY_FEEDFILE + " IN (" + mediaIds + ")", null); + db.delete(TABLE_NAME_FEED_MEDIA, KEY_ID + " IN (" + mediaIds + ")", null); + db.delete(TABLE_NAME_FEED_ITEMS, KEY_ID + " IN (" + itemIds + ")", null); db.setTransactionSuccessful(); } catch (SQLException e) { Log.e(TAG, Log.getStackTraceString(e)); @@ -894,9 +881,7 @@ public class PodDBAdapter { try { db.beginTransactionNonExclusive(); if (feed.getItems() != null) { - for (FeedItem item : feed.getItems()) { - removeFeedItem(item); - } + removeFeedItems(feed.getItems()); } // delete download log entries for feed db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_FEEDFILE + "=? AND " + KEY_FEEDFILETYPE + "=?", @@ -1359,25 +1344,7 @@ public class PodDBAdapter { } /** - * Select number of items, new items, the date of the latest episode and the number of episodes in progress. The result - * is sorted by the title of the feed. - */ - private static final String FEED_STATISTICS_QUERY = "SELECT Feeds.id, num_items, new_items, latest_episode, in_progress FROM " + - " Feeds LEFT JOIN " + - "(SELECT feed,count(*) AS num_items," + - " COUNT(CASE WHEN read=0 THEN 1 END) AS new_items," + - " MAX(pubDate) AS latest_episode," + - " COUNT(CASE WHEN position>0 THEN 1 END) AS in_progress," + - " COUNT(CASE WHEN downloaded=1 THEN 1 END) AS episodes_downloaded " + - " FROM FeedItems LEFT JOIN FeedMedia ON FeedItems.id=FeedMedia.feeditem GROUP BY FeedItems.feed)" + - " ON Feeds.id = feed ORDER BY Feeds.title COLLATE NOCASE ASC;"; - - public Cursor getFeedStatisticsCursor() { - return db.rawQuery(FEED_STATISTICS_QUERY, null); - } - - /** - * Insert raw data to the database. * + * Insert raw data to the database. * Call method only for unit tests. */ @VisibleForTesting(otherwise = VisibleForTesting.NONE) diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 86b3443f3..22607f58b 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -202,8 +202,8 @@ <string name="delete_failed">Unable to delete file. Rebooting the device could help.</string> <string name="delete_episode_label">Delete Episode</string> <plurals name="deleted_multi_episode_batch_label"> - <item quantity="one">%d episode selected, %d download deleted.</item> - <item quantity="other">%d episodes selected, %d download(s) deleted.</item> + <item quantity="one">1 downloaded episode deleted.</item> + <item quantity="other">%d downloaded episodes deleted.</item> </plurals> <string name="remove_new_flag_label">Remove \"new\" flag</string> <string name="removed_new_flag_label">Removed \"new\" flag</string> diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java index f70ed6e29..5e73773db 100644 --- a/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java +++ b/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java @@ -188,14 +188,13 @@ public class DbWriterTest { assertTrue(queue.size() != 0); DBWriter.deleteFeedMediaOfItem(context, media.getId()); - Awaitility.await().until(() -> !dest.exists()); + Awaitility.await().timeout(2, TimeUnit.SECONDS).until(() -> !dest.exists()); media = DBReader.getFeedMedia(media.getId()); assertNotNull(media); assertFalse(dest.exists()); assertFalse(media.isDownloaded()); assertNull(media.getFile_url()); - queue = DBReader.getQueue(); - assertEquals(0, queue.size()); + Awaitility.await().timeout(2, TimeUnit.SECONDS).until(() -> DBReader.getQueue().isEmpty()); } @Test |