diff options
Diffstat (limited to 'core')
11 files changed, 119 insertions, 59 deletions
diff --git a/core/build.gradle b/core/build.gradle index bfaffd14f..b3c614059 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -52,6 +52,16 @@ android { dimension "market" } } + + lintOptions { + disable "InvalidPeriodicWorkRequestInterval", "ObsoleteLintCustomCheck", "DefaultLocale", "UnusedAttribute", + "GradleDependency", "ParcelClassLoader", "Typos", "ExtraTranslation", "ImpliedQuantity", + "PluralsCandidate", "UnusedQuantity", "StringFormatCount", "TrustAllX509TrustManager", + "StaticFieldLeak", "TypographyEllipsis", "IconDensities", "IconDuplicates", "CheckResult" + + warningsAsErrors true + abortOnError true + } } dependencies { diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml index 1f6c36c40..ae5e56e55 100644 --- a/core/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="de.danoeh.antennapod.core"> + xmlns:tools="http://schemas.android.com/tools" package="de.danoeh.antennapod.core"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> @@ -12,15 +12,19 @@ <application android:allowBackup="true" - android:icon="@mipmap/ic_launcher"> + android:icon="@mipmap/ic_launcher" + android:supportsRtl="true"> <service android:name=".service.download.DownloadService" android:enabled="true" /> + <service android:name=".service.playback.PlaybackService" android:label="@string/app_name" android:enabled="true" - android:exported="true"> + android:exported="true" + tools:ignore="ExportedService"> + <intent-filter> <action android:name="android.media.browse.MediaBrowserService"/> </intent-filter> @@ -39,8 +43,8 @@ <receiver android:name=".receiver.FeedUpdateReceiver" android:label="@string/feed_update_receiver_name" - android:exported="true"> <!-- allow feeds update to be triggered by external apps --> - </receiver> + android:exported="true" + tools:ignore="ExportedReceiver" /> <!-- allow feeds update to be triggered by external apps --> </application> </manifest> diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java index 2a2568f28..5ffee0d62 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java @@ -38,11 +38,8 @@ public class FeedPreferences { private int feedSkipEnding; public FeedPreferences(long feedID, boolean autoDownload, AutoDeleteAction auto_delete_action, VolumeAdaptionSetting volumeAdaptionSetting, String username, String password) { - this(feedID, autoDownload, true, auto_delete_action, volumeAdaptionSetting, username, password, new FeedFilter(), SPEED_USE_GLOBAL); - } - - private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, VolumeAdaptionSetting volumeAdaptionSetting, String username, String password, @NonNull FeedFilter filter, float feedPlaybackSpeed) { - this(feedID, autoDownload, true, auto_delete_action, volumeAdaptionSetting, username, password, new FeedFilter(), feedPlaybackSpeed, 0, 0); + this(feedID, autoDownload, true, auto_delete_action, volumeAdaptionSetting, + username, password, new FeedFilter(), SPEED_USE_GLOBAL, 0, 0); } private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, VolumeAdaptionSetting volumeAdaptionSetting, String username, String password, @NonNull FeedFilter filter, float feedPlaybackSpeed, int feedSkipIntro, int feedSkipEnding) { 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 bcbc041a6..5700bb9a0 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 @@ -249,7 +249,7 @@ public class UserPreferences { public static void setFeedOrder(String selected) { prefs.edit() .putString(PREF_DRAWER_FEED_ORDER, selected) - .commit(); + .apply(); } public static int getFeedCounterSetting() { @@ -1054,7 +1054,7 @@ public class UserPreferences { public static void setFeedFilter(String value) { prefs.edit() .putString(PREF_FILTER_FEED, value) - .commit(); + .apply(); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java index 64666d25d..975bc3cb3 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java @@ -153,7 +153,11 @@ public class DownloadServiceNotification { iconId = R.drawable.ic_notification_sync_error; intent = ClientConfig.downloadServiceCallbacks.getReportNotificationContentIntent(context); id = R.id.notification_download_report; - content = String.format(context.getString(R.string.download_report_content), successfulDownloads, failedDownloads); + content = context.getResources() + .getQuantityString(R.plurals.download_report_content, + successfulDownloads, + successfulDownloads, + failedDownloads); } NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java index 883ba6023..9ef34cdac 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java @@ -8,6 +8,7 @@ import androidx.annotation.NonNull; import android.util.Log; import de.danoeh.antennapod.core.preferences.SleepTimerPreferences; +import io.reactivex.disposables.Disposable; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -57,7 +58,7 @@ public class PlaybackServiceTaskManager { private ScheduledFuture<?> widgetUpdaterFuture; private ScheduledFuture<?> sleepTimerFuture; private volatile Future<List<FeedItem>> queueFuture; - private volatile Future<?> chapterLoaderFuture; + private volatile Disposable chapterLoaderFuture; private SleepTimer sleepTimer; @@ -102,7 +103,7 @@ public class PlaybackServiceTaskManager { private synchronized void loadQueue() { if (!isQueueLoaderActive()) { - queueFuture = schedExecutor.submit(DBReader::getQueue); + queueFuture = schedExecutor.submit(() -> DBReader.getQueue()); } } @@ -289,28 +290,19 @@ public class PlaybackServiceTaskManager { } } - private synchronized void cancelChapterLoader() { - if (isChapterLoaderActive()) { - chapterLoaderFuture.cancel(true); - } - } - - private synchronized boolean isChapterLoaderActive() { - return chapterLoaderFuture != null && !chapterLoaderFuture.isDone(); - } - /** * Starts a new thread that loads the chapter marks from a playable object. If another chapter loader is already active, * it will be cancelled first. * On completion, the callback's onChapterLoaded method will be called. */ public synchronized void startChapterLoader(@NonNull final Playable media) { - if (isChapterLoaderActive()) { - cancelChapterLoader(); + if (chapterLoaderFuture != null) { + chapterLoaderFuture.dispose(); + chapterLoaderFuture = null; } if (media.getChapters() == null) { - Completable.create(emitter -> { + chapterLoaderFuture = Completable.create(emitter -> { media.loadChapterMarks(); emitter.onComplete(); }) @@ -330,7 +322,11 @@ public class PlaybackServiceTaskManager { cancelWidgetUpdater(); disableSleepTimer(); cancelQueueLoader(); - cancelChapterLoader(); + + if (chapterLoaderFuture != null) { + chapterLoaderFuture.dispose(); + chapterLoaderFuture = null; + } } /** diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index 16e2825b4..4f2417b7d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -257,7 +257,6 @@ public final class DBTasks { EventBus.getDefault().post(new MessageEvent(context.getString(R.string.error_file_not_found))); } - @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public static List<? extends FeedItem> enqueueFeedItemsToDownload(final Context context, List<? extends FeedItem> items) throws InterruptedException, ExecutionException { List<FeedItem> itemsToEnqueue = new ArrayList<>(); 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 4b585d796..e552cc180 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 @@ -20,7 +20,6 @@ import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; @@ -1207,12 +1206,17 @@ public class PodDBAdapter { * Uses DatabaseUtils to escape a search query and removes ' at the * beginning and the end of the string returned by the escape method. */ - private String prepareSearchQuery(String query) { - StringBuilder builder = new StringBuilder(); - DatabaseUtils.appendEscapedSQLString(builder, query); - builder.deleteCharAt(0); - builder.deleteCharAt(builder.length() - 1); - return builder.toString(); + private String[] prepareSearchQuery(String query) { + String[] queryWords = query.split("\\s+"); + for (int i = 0; i < queryWords.length; ++i) { + StringBuilder builder = new StringBuilder(); + DatabaseUtils.appendEscapedSQLString(builder, queryWords[i]); + builder.deleteCharAt(0); + builder.deleteCharAt(builder.length() - 1); + queryWords[i] = builder.toString(); + } + + return queryWords; } /** @@ -1222,7 +1226,7 @@ public class PodDBAdapter { * @return A cursor with all search results in SEL_FI_EXTRA selection. */ public Cursor searchItems(long feedID, String searchQuery) { - String preparedQuery = prepareSearchQuery(searchQuery); + String[] queryWords = prepareSearchQuery(searchQuery); String queryFeedId; if (feedID != 0) { @@ -1233,14 +1237,28 @@ public class PodDBAdapter { queryFeedId = "1 = 1"; } - String query = SELECT_FEED_ITEMS_AND_MEDIA_WITH_DESCRIPTION - + " WHERE " + queryFeedId + " AND (" - + KEY_DESCRIPTION + " LIKE '%" + preparedQuery + "%' OR " - + KEY_CONTENT_ENCODED + " LIKE '%" + preparedQuery + "%' OR " - + KEY_TITLE + " LIKE '%" + preparedQuery + "%'" - + ") ORDER BY " + KEY_PUBDATE + " DESC " - + "LIMIT 300"; - return db.rawQuery(query, null); + String queryStart = SELECT_FEED_ITEMS_AND_MEDIA_WITH_DESCRIPTION + + " WHERE " + queryFeedId + " AND ("; + StringBuilder sb = new StringBuilder(queryStart); + + for (int i = 0; i < queryWords.length; i++) { + sb + .append("(") + .append(KEY_DESCRIPTION + " LIKE '%").append(queryWords[i]) + .append("%' OR ") + .append(KEY_CONTENT_ENCODED).append(" LIKE '%").append(queryWords[i]) + .append("%' OR ") + .append(KEY_TITLE).append(" LIKE '%").append(queryWords[i]) + .append("%') "); + + if (i != queryWords.length - 1) { + sb.append("AND "); + } + } + + sb.append(") ORDER BY " + KEY_PUBDATE + " DESC LIMIT 300"); + + return db.rawQuery(sb.toString(), null); } /** @@ -1249,15 +1267,31 @@ public class PodDBAdapter { * @return A cursor with all search results in SEL_FI_EXTRA selection. */ public Cursor searchFeeds(String searchQuery) { - String preparedQuery = prepareSearchQuery(searchQuery); - String query = "SELECT * FROM " + TABLE_NAME_FEEDS + " WHERE " - + KEY_TITLE + " LIKE '%" + preparedQuery + "%' OR " - + KEY_CUSTOM_TITLE + " LIKE '%" + preparedQuery + "%' OR " - + KEY_AUTHOR + " LIKE '%" + preparedQuery + "%' OR " - + KEY_DESCRIPTION + " LIKE '%" + preparedQuery + "%' " - + "ORDER BY " + KEY_TITLE + " ASC " - + "LIMIT 300"; - return db.rawQuery(query, null); + String[] queryWords = prepareSearchQuery(searchQuery); + + String queryStart = "SELECT * FROM " + TABLE_NAME_FEEDS + " WHERE "; + StringBuilder sb = new StringBuilder(queryStart); + + for (int i = 0; i < queryWords.length; i++) { + sb + .append("(") + .append(KEY_TITLE).append(" LIKE '%").append(queryWords[i]) + .append("%' OR ") + .append(KEY_CUSTOM_TITLE).append(" LIKE '%").append(queryWords[i]) + .append("%' OR ") + .append(KEY_AUTHOR).append(" LIKE '%").append(queryWords[i]) + .append("%' OR ") + .append(KEY_DESCRIPTION).append(" LIKE '%").append(queryWords[i]) + .append("%') "); + + if (i != queryWords.length - 1) { + sb.append("AND "); + } + } + + sb.append("ORDER BY " + KEY_TITLE + " ASC LIMIT 300"); + + return db.rawQuery(sb.toString(), null); } /** diff --git a/core/src/main/res/layout/player_widget.xml b/core/src/main/res/layout/player_widget.xml index 6e463e9cd..8e38d7f6e 100644 --- a/core/src/main/res/layout/player_widget.xml +++ b/core/src/main/res/layout/player_widget.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/widget_margin" > @@ -8,8 +9,8 @@ android:id="@+id/widgetLayout" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="#262C31" > - + android:background="#262C31" + tools:ignore="UselessParent"> <ImageButton android:id="@+id/butPlay" @@ -41,6 +42,7 @@ android:layout_width="@android:dimen/app_icon_size" android:layout_height="match_parent" android:src="@mipmap/ic_launcher_round" + android:importantForAccessibility="no" android:layout_margin="12dp" /> <LinearLayout diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index f33027f36..23c812f17 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -248,7 +248,10 @@ </plurals> <string name="downloads_processing">Processing downloads</string> <string name="download_notification_title">Downloading podcast data</string> - <string name="download_report_content">%1$d downloads succeeded, %2$d failed</string> + <plurals name="download_report_content"> + <item quantity="one">%d download succeeded, %d failed</item> + <item quantity="other">%d downloads succeeded, %d failed</item> + </plurals> <string name="download_log_title_unknown">Unknown Title</string> <string name="download_type_feed">Feed</string> <string name="download_type_media">Media file</string> @@ -565,6 +568,7 @@ <string name="database_export_summary">Transfer subscriptions, listened episodes and queue to AntennaPod on another device</string> <string name="database_import_summary">Import AntennaPod database from another device</string> <string name="opml_import_label">OPML Import</string> + <string name="opml_add_podcast_label">Import podcast list (OPML)</string> <string name="opml_reader_error">An error has occurred while reading the OPML document:</string> <string name="opml_import_error_no_file">No file selected!</string> <string name="select_all_label">Select all</string> @@ -726,7 +730,7 @@ <string name="search_powered_by">Results by %1$s</string> <string name="filter">Filter</string> - + <!-- Episodes apply actions --> <string name="all_label">All</string> <string name="selected_all_label">Selected all Episodes</string> diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index 73ecdb14e..92faa927a 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -306,4 +306,14 @@ <style name="Widget.AntennaPod.ActionBar.Black" parent="Widget.MaterialComponents.Light.ActionBar.Solid"> <item name="background">@color/black</item> </style> + + <style name="AddPodcastTextView"> + <item name="android:drawablePadding">8dp</item> + <item name="android:paddingTop">8dp</item> + <item name="android:paddingBottom">8dp</item> + <item name="android:background">?android:attr/selectableItemBackground</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:clickable">true</item> + </style> + </resources> |