From edb440a5a9a05e24c344a71b272b9238217e9c55 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 31 Mar 2024 18:40:15 +0200 Subject: Restructure related UI classes together (#7044) --- .../antennapod/core/dialog/ConfirmationDialog.java | 56 ----- .../danoeh/antennapod/core/feed/ChapterMerger.java | 70 ------ .../antennapod/core/feed/FeedItemFilterGroup.java | 37 ---- .../core/feed/SubscriptionsFilterGroup.java | 33 --- .../antennapod/core/menuhandler/MenuItemUtils.java | 28 --- .../core/storage/AutomaticDownloadAlgorithm.java | 21 +- .../danoeh/antennapod/core/util/ChapterMerger.java | 70 ++++++ .../danoeh/antennapod/core/util/ChapterUtils.java | 1 - .../antennapod/core/util/ConfirmationDialog.java | 56 +++++ .../antennapod/core/util/DownloadErrorLabel.java | 46 ---- .../de/danoeh/antennapod/core/util/PowerUtils.java | 30 --- .../de/danoeh/antennapod/core/util/ShareUtils.java | 91 -------- .../core/util/download/MediaSizeLoader.java | 78 ------- .../download/NetworkConnectionChangeHandler.java | 29 --- .../core/util/gui/MoreContentListFooterUtil.java | 53 ----- .../core/util/gui/PictureInPictureUtil.java | 27 --- .../antennapod/core/util/gui/ShownotesCleaner.java | 208 ------------------ .../core/util/syndication/FeedDiscoverer.java | 79 ------- .../core/util/syndication/HtmlToPlainText.java | 123 ----------- core/src/test/java/android/text/TextUtils.java | 42 ---- .../core/feed/VolumeAdaptionSettingTest.java | 129 ----------- .../core/storage/mapper/FeedCursorMapperTest.java | 101 --------- .../danoeh/antennapod/core/util/ConverterTest.java | 40 ---- .../core/util/FeedItemPermutorsTest.java | 231 -------------------- .../core/util/FilenameGeneratorTest.java | 99 --------- .../core/util/gui/ShownotesCleanerTest.java | 236 --------------------- .../core/util/syndication/FeedDiscovererTest.java | 128 ----------- 27 files changed, 144 insertions(+), 1998 deletions(-) delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/feed/ChapterMerger.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/feed/SubscriptionsFilterGroup.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/ChapterMerger.java create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/ConfirmationDialog.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/DownloadErrorLabel.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/download/MediaSizeLoader.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/gui/MoreContentListFooterUtil.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/gui/PictureInPictureUtil.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/gui/ShownotesCleaner.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/syndication/HtmlToPlainText.java delete mode 100644 core/src/test/java/android/text/TextUtils.java delete mode 100644 core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java delete mode 100644 core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java delete mode 100644 core/src/test/java/de/danoeh/antennapod/core/util/ConverterTest.java delete mode 100644 core/src/test/java/de/danoeh/antennapod/core/util/FeedItemPermutorsTest.java delete mode 100644 core/src/test/java/de/danoeh/antennapod/core/util/FilenameGeneratorTest.java delete mode 100644 core/src/test/java/de/danoeh/antennapod/core/util/gui/ShownotesCleanerTest.java delete mode 100644 core/src/test/java/de/danoeh/antennapod/core/util/syndication/FeedDiscovererTest.java (limited to 'core') diff --git a/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java b/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java deleted file mode 100644 index b964c7508..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java +++ /dev/null @@ -1,56 +0,0 @@ -package de.danoeh.antennapod.core.dialog; - -import android.content.Context; -import android.content.DialogInterface; -import androidx.appcompat.app.AlertDialog; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import android.util.Log; - -import de.danoeh.antennapod.core.R; - -/** - * Creates an AlertDialog which asks the user to confirm something. Other - * classes can handle events like confirmation or cancellation. - */ -public abstract class ConfirmationDialog { - - private static final String TAG = ConfirmationDialog.class.getSimpleName(); - - private final Context context; - private final int titleId; - private final String message; - - private int positiveText; - - public ConfirmationDialog(Context context, int titleId, int messageId) { - this(context, titleId, context.getString(messageId)); - } - - public ConfirmationDialog(Context context, int titleId, String message) { - this.context = context; - this.titleId = titleId; - this.message = message; - } - - private void onCancelButtonPressed(DialogInterface dialog) { - Log.d(TAG, "Dialog was cancelled"); - dialog.dismiss(); - } - - public void setPositiveText(int id) { - this.positiveText = id; - } - - public abstract void onConfirmButtonPressed(DialogInterface dialog); - - public final AlertDialog createNewDialog() { - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context); - builder.setTitle(titleId); - builder.setMessage(message); - builder.setPositiveButton(positiveText != 0 ? positiveText : R.string.confirm_label, - (dialog, which) -> onConfirmButtonPressed(dialog)); - builder.setNegativeButton(R.string.cancel_label, (dialog, which) -> onCancelButtonPressed(dialog)); - builder.setOnCancelListener(ConfirmationDialog.this::onCancelButtonPressed); - return builder.create(); - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/ChapterMerger.java b/core/src/main/java/de/danoeh/antennapod/core/feed/ChapterMerger.java deleted file mode 100644 index 9bbab7251..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/ChapterMerger.java +++ /dev/null @@ -1,70 +0,0 @@ -package de.danoeh.antennapod.core.feed; - -import android.text.TextUtils; -import android.util.Log; -import androidx.annotation.Nullable; -import de.danoeh.antennapod.model.feed.Chapter; - -import java.util.List; - -public class ChapterMerger { - private static final String TAG = "ChapterMerger"; - - private ChapterMerger() { - - } - - /** - * This method might modify the input data. - */ - @Nullable - public static List merge(@Nullable List chapters1, @Nullable List chapters2) { - Log.d(TAG, "Merging chapters"); - if (chapters1 == null) { - return chapters2; - } else if (chapters2 == null) { - return chapters1; - } else if (chapters2.size() > chapters1.size()) { - return chapters2; - } else if (chapters2.size() < chapters1.size()) { - return chapters1; - } else { - // Merge chapter lists of same length. Store in chapters2 array. - // In case the lists can not be merged, return chapters1 array. - for (int i = 0; i < chapters2.size(); i++) { - Chapter chapterTarget = chapters2.get(i); - Chapter chapterOther = chapters1.get(i); - - if (Math.abs(chapterTarget.getStart() - chapterOther.getStart()) > 1000) { - Log.e(TAG, "Chapter lists are too different. Cancelling merge."); - return score(chapters1) > score(chapters2) ? chapters1 : chapters2; - } - - if (TextUtils.isEmpty(chapterTarget.getImageUrl())) { - chapterTarget.setImageUrl(chapterOther.getImageUrl()); - } - if (TextUtils.isEmpty(chapterTarget.getLink())) { - chapterTarget.setLink(chapterOther.getLink()); - } - if (TextUtils.isEmpty(chapterTarget.getTitle())) { - chapterTarget.setTitle(chapterOther.getTitle()); - } - } - return chapters2; - } - } - - /** - * Tries to give a score that can determine which list of chapters a user might want to see. - */ - private static int score(List chapters) { - int score = 0; - for (Chapter chapter : chapters) { - score = score - + (TextUtils.isEmpty(chapter.getTitle()) ? 0 : 1) - + (TextUtils.isEmpty(chapter.getLink()) ? 0 : 1) - + (TextUtils.isEmpty(chapter.getImageUrl()) ? 0 : 1); - } - return score; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java deleted file mode 100644 index fbdf6b3a9..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java +++ /dev/null @@ -1,37 +0,0 @@ -package de.danoeh.antennapod.core.feed; - -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.model.feed.FeedItemFilter; - -public enum FeedItemFilterGroup { - PLAYED(new ItemProperties(R.string.hide_played_episodes_label, FeedItemFilter.PLAYED), - new ItemProperties(R.string.not_played, FeedItemFilter.UNPLAYED)), - PAUSED(new ItemProperties(R.string.hide_paused_episodes_label, FeedItemFilter.PAUSED), - new ItemProperties(R.string.not_paused, FeedItemFilter.NOT_PAUSED)), - FAVORITE(new ItemProperties(R.string.hide_is_favorite_label, FeedItemFilter.IS_FAVORITE), - new ItemProperties(R.string.not_favorite, FeedItemFilter.NOT_FAVORITE)), - MEDIA(new ItemProperties(R.string.has_media, FeedItemFilter.HAS_MEDIA), - new ItemProperties(R.string.no_media, FeedItemFilter.NO_MEDIA)), - QUEUED(new ItemProperties(R.string.queued_label, FeedItemFilter.QUEUED), - new ItemProperties(R.string.not_queued_label, FeedItemFilter.NOT_QUEUED)), - DOWNLOADED(new ItemProperties(R.string.hide_downloaded_episodes_label, FeedItemFilter.DOWNLOADED), - new ItemProperties(R.string.hide_not_downloaded_episodes_label, FeedItemFilter.NOT_DOWNLOADED)); - - public final ItemProperties[] values; - - FeedItemFilterGroup(ItemProperties... values) { - this.values = values; - } - - public static class ItemProperties { - - public final int displayName; - public final String filterId; - - public ItemProperties(int displayName, String filterId) { - this.displayName = displayName; - this.filterId = filterId; - } - - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/SubscriptionsFilterGroup.java b/core/src/main/java/de/danoeh/antennapod/core/feed/SubscriptionsFilterGroup.java deleted file mode 100644 index cea5d96ef..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/SubscriptionsFilterGroup.java +++ /dev/null @@ -1,33 +0,0 @@ -package de.danoeh.antennapod.core.feed; - -import de.danoeh.antennapod.core.R; - -public enum SubscriptionsFilterGroup { - COUNTER_GREATER_ZERO(new ItemProperties(R.string.subscriptions_counter_greater_zero, "counter_greater_zero")), - AUTO_DOWNLOAD(new ItemProperties(R.string.auto_downloaded, "enabled_auto_download"), - new ItemProperties(R.string.not_auto_downloaded, "disabled_auto_download")), - UPDATED(new ItemProperties(R.string.kept_updated, "enabled_updates"), - new ItemProperties(R.string.not_kept_updated, "disabled_updates")), - NEW_EPISODE_NOTIFICATION(new ItemProperties(R.string.new_episode_notification_enabled, - "episode_notification_enabled"), - new ItemProperties(R.string.new_episode_notification_disabled, "episode_notification_disabled")); - - - public final ItemProperties[] values; - - SubscriptionsFilterGroup(ItemProperties... values) { - this.values = values; - } - - public static class ItemProperties { - - public final int displayName; - public final String filterId; - - public ItemProperties(int displayName, String filterId) { - this.displayName = displayName; - this.filterId = filterId; - } - - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java b/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java deleted file mode 100644 index 829add126..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java +++ /dev/null @@ -1,28 +0,0 @@ -package de.danoeh.antennapod.core.menuhandler; - -import android.view.Menu; -import android.view.MenuItem; - -/** - * Utilities for menu items - */ -public class MenuItemUtils { - - /** - * When pressing a context menu item, Android calls onContextItemSelected - * for ALL fragments in arbitrary order, not just for the fragment that the - * context menu was created from. This assigns the listener to every menu item, - * so that the correct fragment is always called first and can consume the click. - *

- * Note that Android still calls the onContextItemSelected methods of all fragments - * when the passed listener returns false. - */ - public static void setOnClickListeners(Menu menu, MenuItem.OnMenuItemClickListener listener) { - for (int i = 0; i < menu.size(); i++) { - if (menu.getItem(i).getSubMenu() != null) { - setOnClickListeners(menu.getItem(i).getSubMenu(), listener); - } - menu.getItem(i).setOnMenuItemClickListener(listener); - } - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java index 93f7d578a..dbcc899ba 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java @@ -1,6 +1,9 @@ package de.danoeh.antennapod.core.storage; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; import android.util.Log; import java.util.ArrayList; @@ -15,7 +18,6 @@ import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterfa import de.danoeh.antennapod.storage.database.DBReader; import de.danoeh.antennapod.storage.preferences.UserPreferences; import de.danoeh.antennapod.net.common.NetworkUtils; -import de.danoeh.antennapod.core.util.PowerUtils; /** * Implements the automatic download algorithm used by AntennaPod. This class assumes that @@ -42,8 +44,7 @@ public class AutomaticDownloadAlgorithm { && UserPreferences.isEnableAutodownload(); // true if we should auto download based on power status - boolean powerShouldAutoDl = PowerUtils.deviceCharging(context) - || UserPreferences.isEnableAutodownloadOnBattery(); + boolean powerShouldAutoDl = deviceCharging(context) || UserPreferences.isEnableAutodownloadOnBattery(); // we should only auto download if both network AND power are happy if (networkShouldAutoDl && powerShouldAutoDl) { @@ -103,4 +104,18 @@ public class AutomaticDownloadAlgorithm { } }; } + + /** + * @return true if the device is charging + */ + public static boolean deviceCharging(Context context) { + // from http://developer.android.com/training/monitoring-device-state/battery-monitoring.html + IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + Intent batteryStatus = context.registerReceiver(null, intentFilter); + + int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + return (status == BatteryManager.BATTERY_STATUS_CHARGING + || status == BatteryManager.BATTERY_STATUS_FULL); + + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterMerger.java b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterMerger.java new file mode 100644 index 000000000..794b2322d --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterMerger.java @@ -0,0 +1,70 @@ +package de.danoeh.antennapod.core.util; + +import android.text.TextUtils; +import android.util.Log; +import androidx.annotation.Nullable; +import de.danoeh.antennapod.model.feed.Chapter; + +import java.util.List; + +public class ChapterMerger { + private static final String TAG = "ChapterMerger"; + + private ChapterMerger() { + + } + + /** + * This method might modify the input data. + */ + @Nullable + public static List merge(@Nullable List chapters1, @Nullable List chapters2) { + Log.d(TAG, "Merging chapters"); + if (chapters1 == null) { + return chapters2; + } else if (chapters2 == null) { + return chapters1; + } else if (chapters2.size() > chapters1.size()) { + return chapters2; + } else if (chapters2.size() < chapters1.size()) { + return chapters1; + } else { + // Merge chapter lists of same length. Store in chapters2 array. + // In case the lists can not be merged, return chapters1 array. + for (int i = 0; i < chapters2.size(); i++) { + Chapter chapterTarget = chapters2.get(i); + Chapter chapterOther = chapters1.get(i); + + if (Math.abs(chapterTarget.getStart() - chapterOther.getStart()) > 1000) { + Log.e(TAG, "Chapter lists are too different. Cancelling merge."); + return score(chapters1) > score(chapters2) ? chapters1 : chapters2; + } + + if (TextUtils.isEmpty(chapterTarget.getImageUrl())) { + chapterTarget.setImageUrl(chapterOther.getImageUrl()); + } + if (TextUtils.isEmpty(chapterTarget.getLink())) { + chapterTarget.setLink(chapterOther.getLink()); + } + if (TextUtils.isEmpty(chapterTarget.getTitle())) { + chapterTarget.setTitle(chapterOther.getTitle()); + } + } + return chapters2; + } + } + + /** + * Tries to give a score that can determine which list of chapters a user might want to see. + */ + private static int score(List chapters) { + int score = 0; + for (Chapter chapter : chapters) { + score = score + + (TextUtils.isEmpty(chapter.getTitle()) ? 0 : 1) + + (TextUtils.isEmpty(chapter.getLink()) ? 0 : 1) + + (TextUtils.isEmpty(chapter.getImageUrl()) ? 0 : 1); + } + return score; + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java index 1af81802b..b32b05236 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java @@ -7,7 +7,6 @@ import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; import de.danoeh.antennapod.model.feed.Chapter; -import de.danoeh.antennapod.core.feed.ChapterMerger; import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.net.common.AntennapodHttpClient; import de.danoeh.antennapod.storage.database.DBReader; diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ConfirmationDialog.java b/core/src/main/java/de/danoeh/antennapod/core/util/ConfirmationDialog.java new file mode 100644 index 000000000..ff5e56f5d --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ConfirmationDialog.java @@ -0,0 +1,56 @@ +package de.danoeh.antennapod.core.util; + +import android.content.Context; +import android.content.DialogInterface; +import androidx.appcompat.app.AlertDialog; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import android.util.Log; + +import de.danoeh.antennapod.core.R; + +/** + * Creates an AlertDialog which asks the user to confirm something. Other + * classes can handle events like confirmation or cancellation. + */ +public abstract class ConfirmationDialog { + + private static final String TAG = ConfirmationDialog.class.getSimpleName(); + + private final Context context; + private final int titleId; + private final String message; + + private int positiveText; + + public ConfirmationDialog(Context context, int titleId, int messageId) { + this(context, titleId, context.getString(messageId)); + } + + public ConfirmationDialog(Context context, int titleId, String message) { + this.context = context; + this.titleId = titleId; + this.message = message; + } + + private void onCancelButtonPressed(DialogInterface dialog) { + Log.d(TAG, "Dialog was cancelled"); + dialog.dismiss(); + } + + public void setPositiveText(int id) { + this.positiveText = id; + } + + public abstract void onConfirmButtonPressed(DialogInterface dialog); + + public final AlertDialog createNewDialog() { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context); + builder.setTitle(titleId); + builder.setMessage(message); + builder.setPositiveButton(positiveText != 0 ? positiveText : R.string.confirm_label, + (dialog, which) -> onConfirmButtonPressed(dialog)); + builder.setNegativeButton(R.string.cancel_label, (dialog, which) -> onCancelButtonPressed(dialog)); + builder.setOnCancelListener(ConfirmationDialog.this::onCancelButtonPressed); + return builder.create(); + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DownloadErrorLabel.java b/core/src/main/java/de/danoeh/antennapod/core/util/DownloadErrorLabel.java deleted file mode 100644 index 3d2558a9f..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/DownloadErrorLabel.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import androidx.annotation.StringRes; -import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.model.download.DownloadError; - -/** - * Provides user-visible labels for download errors. - */ -public class DownloadErrorLabel { - - @StringRes - public static int from(DownloadError error) { - switch (error) { - case SUCCESS: return R.string.download_successful; - case ERROR_PARSER_EXCEPTION: return R.string.download_error_parser_exception; - case ERROR_UNSUPPORTED_TYPE: return R.string.download_error_unsupported_type; - case ERROR_CONNECTION_ERROR: return R.string.download_error_connection_error; - case ERROR_MALFORMED_URL: return R.string.download_error_error_unknown; - case ERROR_IO_ERROR: return R.string.download_error_io_error; - case ERROR_FILE_EXISTS: return R.string.download_error_error_unknown; - case ERROR_DOWNLOAD_CANCELLED: return R.string.download_canceled_msg; - case ERROR_DEVICE_NOT_FOUND: return R.string.download_error_device_not_found; - case ERROR_HTTP_DATA_ERROR: return R.string.download_error_http_data_error; - case ERROR_NOT_ENOUGH_SPACE: return R.string.download_error_insufficient_space; - case ERROR_UNKNOWN_HOST: return R.string.download_error_unknown_host; - case ERROR_REQUEST_ERROR: return R.string.download_error_request_error; - case ERROR_DB_ACCESS_ERROR: return R.string.download_error_db_access; - case ERROR_UNAUTHORIZED: return R.string.download_error_unauthorized; - case ERROR_FILE_TYPE: return R.string.download_error_file_type_type; - case ERROR_FORBIDDEN: return R.string.download_error_forbidden; - case ERROR_IO_WRONG_SIZE: return R.string.download_error_wrong_size; - case ERROR_IO_BLOCKED: return R.string.download_error_blocked; - case ERROR_UNSUPPORTED_TYPE_HTML: return R.string.download_error_unsupported_type_html; - case ERROR_NOT_FOUND: return R.string.download_error_not_found; - case ERROR_CERTIFICATE: return R.string.download_error_certificate; - case ERROR_PARSER_EXCEPTION_DUPLICATE: return R.string.download_error_parser_exception; - default: - if (BuildConfig.DEBUG) { - throw new IllegalArgumentException("No mapping from download error to label"); - } - return R.string.download_error_error_unknown; - } - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java deleted file mode 100644 index a1fadb4dc..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.BatteryManager; - -/** - * Created by Tom on 1/5/15. - */ -public class PowerUtils { - - private PowerUtils() { - - } - - /** - * @return true if the device is charging - */ - public static boolean deviceCharging(Context context) { - // from http://developer.android.com/training/monitoring-device-state/battery-monitoring.html - IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - Intent batteryStatus = context.registerReceiver(null, iFilter); - - int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); - return (status == BatteryManager.BATTERY_STATUS_CHARGING || - status == BatteryManager.BATTERY_STATUS_FULL); - - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java deleted file mode 100644 index 316771123..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java +++ /dev/null @@ -1,91 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.core.app.ShareCompat; -import androidx.core.content.FileProvider; - -import de.danoeh.antennapod.ui.common.Converter; -import java.io.File; -import java.net.URLEncoder; - -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.model.feed.Feed; -import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.model.feed.FeedMedia; - -/** Utility methods for sharing data */ -public class ShareUtils { - private static final String TAG = "ShareUtils"; - - private ShareUtils() { - } - - public static void shareLink(@NonNull Context context, @NonNull String text) { - Intent intent = new ShareCompat.IntentBuilder(context) - .setType("text/plain") - .setText(text) - .setChooserTitle(R.string.share_url_label) - .createChooserIntent(); - context.startActivity(intent); - } - - public static void shareFeedLink(Context context, Feed feed) { - String text = feed.getTitle() - + "\n\n" - + "https://antennapod.org/deeplink/subscribe/?url=" - + URLEncoder.encode(feed.getDownloadUrl()) - + "&title=" - + URLEncoder.encode(feed.getTitle()); - shareLink(context, text); - } - - public static boolean hasLinkToShare(FeedItem item) { - return FeedItemUtil.getLinkWithFallback(item) != null; - } - - public static void shareMediaDownloadLink(Context context, FeedMedia media) { - shareLink(context, media.getDownloadUrl()); - } - - public static void shareFeedItemLinkWithDownloadLink(Context context, FeedItem item, boolean withPosition) { - String text = item.getFeed().getTitle() + ": " + item.getTitle(); - int pos = 0; - if (item.getMedia() != null && withPosition) { - text += "\n" + context.getResources().getString(R.string.share_starting_position_label) + ": "; - pos = item.getMedia().getPosition(); - text += Converter.getDurationStringLong(pos); - } - - if (hasLinkToShare(item)) { - text += "\n\n" + context.getResources().getString(R.string.share_dialog_episode_website_label) + ": "; - text += FeedItemUtil.getLinkWithFallback(item); - } - - if (item.getMedia() != null && item.getMedia().getDownloadUrl() != null) { - text += "\n\n" + context.getResources().getString(R.string.share_dialog_media_file_label) + ": "; - text += item.getMedia().getDownloadUrl(); - if (withPosition) { - text += "#t=" + pos / 1000; - } - } - shareLink(context, text); - } - - public static void shareFeedItemFile(Context context, FeedMedia media) { - Uri fileUri = FileProvider.getUriForFile(context, context.getString(R.string.provider_authority), - new File(media.getLocalFileUrl())); - - new ShareCompat.IntentBuilder(context) - .setType(media.getMimeType()) - .addStream(fileUri) - .setChooserTitle(R.string.share_file_label) - .startChooser(); - - Log.e(TAG, "shareFeedItemFile called"); - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/MediaSizeLoader.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/MediaSizeLoader.java deleted file mode 100644 index 779f3b947..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/download/MediaSizeLoader.java +++ /dev/null @@ -1,78 +0,0 @@ -package de.danoeh.antennapod.core.util.download; - -import android.text.TextUtils; -import de.danoeh.antennapod.net.common.AntennapodHttpClient; -import de.danoeh.antennapod.storage.database.DBWriter; -import de.danoeh.antennapod.net.common.NetworkUtils; -import de.danoeh.antennapod.model.feed.FeedMedia; -import io.reactivex.Single; -import io.reactivex.SingleOnSubscribe; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import android.util.Log; -import okhttp3.Response; - -import java.io.File; -import java.io.IOException; - -public abstract class MediaSizeLoader { - private static final String TAG = "MediaSizeLoader"; - - public static Single getFeedMediaSizeObservable(FeedMedia media) { - return Single.create((SingleOnSubscribe) emitter -> { - if (!NetworkUtils.isEpisodeHeadDownloadAllowed()) { - emitter.onSuccess(0L); - return; - } - long size = Integer.MIN_VALUE; - if (media.isDownloaded()) { - File mediaFile = new File(media.getLocalFileUrl()); - if (mediaFile.exists()) { - size = mediaFile.length(); - } - } else if (!media.checkedOnSizeButUnknown()) { - // only query the network if we haven't already checked - - String url = media.getDownloadUrl(); - if (TextUtils.isEmpty(url)) { - emitter.onSuccess(0L); - return; - } - - OkHttpClient client = AntennapodHttpClient.getHttpClient(); - Request.Builder httpReq = new Request.Builder() - .url(url) - .header("Accept-Encoding", "identity") - .head(); - try { - Response response = client.newCall(httpReq.build()).execute(); - if (response.isSuccessful()) { - String contentLength = response.header("Content-Length"); - try { - size = Integer.parseInt(contentLength); - } catch (NumberFormatException e) { - Log.e(TAG, Log.getStackTraceString(e)); - } - } - } catch (IOException e) { - emitter.onSuccess(0L); - Log.e(TAG, Log.getStackTraceString(e)); - return; // better luck next time - } - } - Log.d(TAG, "new size: " + size); - if (size <= 0) { - // they didn't tell us the size, but we don't want to keep querying on it - media.setCheckedOnSizeButUnknown(); - } else { - media.setSize(size); - } - emitter.onSuccess(size); - DBWriter.setFeedMedia(media); - }) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()); - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java deleted file mode 100644 index 79c6e76e1..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/download/NetworkConnectionChangeHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.danoeh.antennapod.core.util.download; - -import android.content.Context; -import android.util.Log; -import de.danoeh.antennapod.net.download.serviceinterface.AutoDownloadManager; -import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface; -import de.danoeh.antennapod.net.common.NetworkUtils; - -public abstract class NetworkConnectionChangeHandler { - private static final String TAG = "NetConnChangeHandler"; - private static Context context; - - public static void init(Context context) { - NetworkConnectionChangeHandler.context = context; - } - - public static void networkChangedDetected() { - if (NetworkUtils.isAutoDownloadAllowed()) { - Log.d(TAG, "auto-dl network available, starting auto-download"); - AutoDownloadManager.getInstance().autodownloadUndownloadedItems(context); - } else { // if new network is Wi-Fi, finish ongoing downloads, - // otherwise cancel all downloads - if (NetworkUtils.isNetworkRestricted()) { - Log.i(TAG, "Device is no longer connected to Wi-Fi. Cancelling ongoing downloads"); - DownloadServiceInterface.get().cancelAll(context); - } - } - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/gui/MoreContentListFooterUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/gui/MoreContentListFooterUtil.java deleted file mode 100644 index 6e5c3e84b..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/gui/MoreContentListFooterUtil.java +++ /dev/null @@ -1,53 +0,0 @@ -package de.danoeh.antennapod.core.util.gui; - -import android.view.View; -import android.widget.ImageView; -import android.widget.ProgressBar; - -import de.danoeh.antennapod.core.R; - -/** - * Utility methods for the more_content_list_footer layout. - */ -public class MoreContentListFooterUtil { - - private final View root; - - private boolean loading; - - private Listener listener; - - public MoreContentListFooterUtil(View root) { - this.root = root; - root.setOnClickListener(v -> { - if (listener != null && !loading) { - listener.onClick(); - } - }); - } - - public void setLoadingState(boolean newState) { - final ImageView imageView = root.findViewById(R.id.imgExpand); - final ProgressBar progressBar = root.findViewById(R.id.progBar); - if (newState) { - imageView.setVisibility(View.GONE); - progressBar.setVisibility(View.VISIBLE); - } else { - imageView.setVisibility(View.VISIBLE); - progressBar.setVisibility(View.GONE); - } - loading = newState; - } - - public void setClickListener(Listener l) { - listener = l; - } - - public interface Listener { - void onClick(); - } - - public View getRoot() { - return root; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/gui/PictureInPictureUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/gui/PictureInPictureUtil.java deleted file mode 100644 index f763653a1..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/gui/PictureInPictureUtil.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.danoeh.antennapod.core.util.gui; - -import android.app.Activity; -import android.content.pm.PackageManager; -import android.os.Build; - -public class PictureInPictureUtil { - private PictureInPictureUtil() { - } - - public static boolean supportsPictureInPicture(Activity activity) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - PackageManager packageManager = activity.getPackageManager(); - return packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE); - } else { - return false; - } - } - - public static boolean isInPictureInPictureMode(Activity activity) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && supportsPictureInPicture(activity)) { - return activity.isInPictureInPictureMode(); - } else { - return false; - } - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/gui/ShownotesCleaner.java b/core/src/main/java/de/danoeh/antennapod/core/util/gui/ShownotesCleaner.java deleted file mode 100644 index 7bf9257a1..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/gui/ShownotesCleaner.java +++ /dev/null @@ -1,208 +0,0 @@ -package de.danoeh.antennapod.core.util.gui; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Color; -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import android.text.TextUtils; -import android.util.Log; -import android.util.TypedValue; - -import androidx.annotation.Nullable; -import org.apache.commons.io.IOUtils; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.ui.common.Converter; - -/** - * Cleans up and prepares shownotes: - * - Guesses time stamps to make them clickable - * - Removes some formatting - */ -public class ShownotesCleaner { - private static final String TAG = "Timeline"; - - private static final Pattern TIMECODE_LINK_REGEX = Pattern.compile("antennapod://timecode/(\\d+)"); - private static final String TIMECODE_LINK = "%s"; - private static final Pattern TIMECODE_REGEX = Pattern.compile("\\b((\\d+):)?(\\d+):(\\d{2})\\b"); - private static final Pattern LINE_BREAK_REGEX = Pattern.compile("
"); - private static final String CSS_COLOR = "(?<=(\\s|;|^))color\\s*:([^;])*;"; - private static final String CSS_COMMENT = "/\\*.*?\\*/"; - - private final String rawShownotes; - private final String noShownotesLabel; - private final int playableDuration; - private final String webviewStyle; - - public ShownotesCleaner(Context context, @Nullable String rawShownotes, int playableDuration) { - this.rawShownotes = rawShownotes; - - noShownotesLabel = context.getString(R.string.no_shownotes_label); - this.playableDuration = playableDuration; - final String colorPrimary = colorToHtml(context, android.R.attr.textColorPrimary); - final String colorAccent = colorToHtml(context, R.attr.colorAccent); - final int margin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, - context.getResources().getDisplayMetrics()); - String styleString = ""; - try { - InputStream templateStream = context.getAssets().open("shownotes-style.css"); - styleString = IOUtils.toString(templateStream, "UTF-8"); - } catch (IOException e) { - e.printStackTrace(); - } - webviewStyle = String.format(Locale.US, styleString, colorPrimary, colorAccent, - margin, margin, margin, margin); - } - - private String colorToHtml(Context context, int colorAttr) { - TypedArray res = context.getTheme().obtainStyledAttributes(new int[]{colorAttr}); - @ColorInt int col = res.getColor(0, 0); - final String color = "rgba(" + Color.red(col) + "," + Color.green(col) + "," - + Color.blue(col) + "," + (Color.alpha(col) / 255.0) + ")"; - res.recycle(); - return color; - } - - /** - * Applies an app-specific CSS stylesheet and adds timecode links (optional). - *

- * This method does NOT change the original shownotes string of the shownotesProvider object and it should - * also not be changed by the caller. - * - * @return The processed HTML string. - */ - @NonNull - public String processShownotes() { - String shownotes = rawShownotes; - - if (TextUtils.isEmpty(shownotes)) { - Log.d(TAG, "shownotesProvider contained no shownotes. Returning 'no shownotes' message"); - shownotes = "

" + noShownotesLabel + "

"; - } - - // replace ASCII line breaks with HTML ones if shownotes don't contain HTML line breaks already - if (!LINE_BREAK_REGEX.matcher(shownotes).find() && !shownotes.contains("

")) { - shownotes = shownotes.replace("\n", "
"); - } - - Document document = Jsoup.parse(shownotes); - cleanCss(document); - document.head().appendElement("style").attr("type", "text/css").text(webviewStyle); - addTimecodes(document); - return document.toString(); - } - - /** - * Returns true if the given link is a timecode link. - */ - public static boolean isTimecodeLink(String link) { - return link != null && link.matches(TIMECODE_LINK_REGEX.pattern()); - } - - /** - * Returns the time in milliseconds that is attached to this link or -1 - * if the link is no valid timecode link. - */ - public static int getTimecodeLinkTime(String link) { - if (isTimecodeLink(link)) { - Matcher m = TIMECODE_LINK_REGEX.matcher(link); - - try { - if (m.find()) { - return Integer.parseInt(m.group(1)); - } - } catch (NumberFormatException e) { - e.printStackTrace(); - } - } - return -1; - } - - private void addTimecodes(Document document) { - Elements elementsWithTimeCodes = document.body().getElementsMatchingOwnText(TIMECODE_REGEX); - Log.d(TAG, "Recognized " + elementsWithTimeCodes.size() + " timecodes"); - - if (elementsWithTimeCodes.size() == 0) { - // No elements with timecodes - return; - } - boolean useHourFormat = true; - - if (playableDuration != Integer.MAX_VALUE) { - - // We need to decide if we are going to treat short timecodes as HH:MM or MM:SS. To do - // so we will parse all the short timecodes and see if they fit in the duration. If one - // does not we will use MM:SS, otherwise all will be parsed as HH:MM. - for (Element element : elementsWithTimeCodes) { - Matcher matcherForElement = TIMECODE_REGEX.matcher(element.html()); - while (matcherForElement.find()) { - - // We only want short timecodes right now. - if (matcherForElement.group(1) == null) { - int time = Converter.durationStringShortToMs(matcherForElement.group(0), true); - - // If the parsed timecode is greater then the duration then we know we need to - // use the minute format so we are done. - if (time > playableDuration) { - useHourFormat = false; - break; - } - } - } - - if (!useHourFormat) { - break; - } - } - } - - for (Element element : elementsWithTimeCodes) { - - Matcher matcherForElement = TIMECODE_REGEX.matcher(element.html()); - StringBuffer buffer = new StringBuffer(); - - while (matcherForElement.find()) { - String group = matcherForElement.group(0); - - int time = matcherForElement.group(1) != null - ? Converter.durationStringLongToMs(group) - : Converter.durationStringShortToMs(group, useHourFormat); - - String replacementText = group; - if (time < playableDuration) { - replacementText = String.format(Locale.US, TIMECODE_LINK, time, group); - } - - matcherForElement.appendReplacement(buffer, replacementText); - } - - matcherForElement.appendTail(buffer); - element.html(buffer.toString()); - } - } - - private void cleanCss(Document document) { - for (Element element : document.getAllElements()) { - if (element.hasAttr("style")) { - element.attr("style", element.attr("style").replaceAll(CSS_COLOR, "")); - } else if (element.tagName().equals("style")) { - element.html(cleanStyleTag(element.html())); - } - } - } - - public static String cleanStyleTag(String oldCss) { - return oldCss.replaceAll(CSS_COMMENT, "").replaceAll(CSS_COLOR, ""); - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java deleted file mode 100644 index 316608f2f..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java +++ /dev/null @@ -1,79 +0,0 @@ -package de.danoeh.antennapod.core.util.syndication; - -import android.net.Uri; -import androidx.collection.ArrayMap; -import android.text.TextUtils; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import java.io.File; -import java.io.IOException; -import java.util.Map; - -/** - * Finds RSS/Atom URLs in a HTML document using the auto-discovery techniques described here: - *

- * http://www.rssboard.org/rss-autodiscovery - *

- * http://blog.whatwg.org/feed-autodiscovery - */ -public class FeedDiscoverer { - - private static final String MIME_RSS = "application/rss+xml"; - private static final String MIME_ATOM = "application/atom+xml"; - - /** - * Discovers links to RSS and Atom feeds in the given File which must be a HTML document. - * - * @return A map which contains the feed URLs as keys and titles as values (the feed URL is also used as a title if - * a title cannot be found). - */ - public Map findLinks(File in, String baseUrl) throws IOException { - return findLinks(Jsoup.parse(in), baseUrl); - } - - /** - * Discovers links to RSS and Atom feeds in the given File which must be a HTML document. - * - * @return A map which contains the feed URLs as keys and titles as values (the feed URL is also used as a title if - * a title cannot be found). - */ - public Map findLinks(String in, String baseUrl) { - return findLinks(Jsoup.parse(in), baseUrl); - } - - private Map findLinks(Document document, String baseUrl) { - Map res = new ArrayMap<>(); - Elements links = document.head().getElementsByTag("link"); - for (Element link : links) { - String rel = link.attr("rel"); - String href = link.attr("href"); - if (!TextUtils.isEmpty(href) && - (rel.equals("alternate") || rel.equals("feed"))) { - String type = link.attr("type"); - if (type.equals(MIME_RSS) || type.equals(MIME_ATOM)) { - String title = link.attr("title"); - String processedUrl = processURL(baseUrl, href); - if (processedUrl != null) { - res.put(processedUrl, - (TextUtils.isEmpty(title)) ? href : title); - } - } - } - } - return res; - } - - private String processURL(String baseUrl, String strUrl) { - Uri uri = Uri.parse(strUrl); - if (uri.isRelative()) { - Uri res = Uri.parse(baseUrl).buildUpon().path(strUrl).build(); - return (res != null) ? res.toString() : null; - } else { - return strUrl; - } - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/HtmlToPlainText.java b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/HtmlToPlainText.java deleted file mode 100644 index c5f0727c2..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/HtmlToPlainText.java +++ /dev/null @@ -1,123 +0,0 @@ -package de.danoeh.antennapod.core.util.syndication; - -import android.text.TextUtils; - -import org.apache.commons.lang3.StringUtils; -import org.jsoup.Jsoup; -import org.jsoup.internal.StringUtil; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; -import org.jsoup.nodes.TextNode; -import org.jsoup.select.NodeTraversor; -import org.jsoup.select.NodeVisitor; - -import java.util.regex.Pattern; - -/** - * This class is based on HtmlToPlainText from jsoup's examples package. - * - * HTML to plain-text. This example program demonstrates the use of jsoup to convert HTML input to lightly-formatted - * plain-text. That is divergent from the general goal of jsoup's .text() methods, which is to get clean data from a - * scrape. - *

- * Note that this is a fairly simplistic formatter -- for real world use you'll want to embrace and extend. - *

- *

- * To invoke from the command line, assuming you've downloaded the jsoup jar to your current directory:

- *

java -cp jsoup.jar org.jsoup.examples.HtmlToPlainText url [selector]

- * where url is the URL to fetch, and selector is an optional CSS selector. - * - * @author Jonathan Hedley, jonathan@hedley.net - * @author AntennaPod open source community - */ -public class HtmlToPlainText { - - /** - * Use this method to strip off HTML encoding from given text. - * Replaces bullet points with *, ignores colors/bold/... - * - * @param str String with any encoding - * @return Human readable text with minimal HTML formatting - */ - public static String getPlainText(String str) { - if (!TextUtils.isEmpty(str) && isHtml(str)) { - HtmlToPlainText formatter = new HtmlToPlainText(); - Document feedDescription = Jsoup.parse(str); - str = StringUtils.trim(formatter.getPlainText(feedDescription)); - } else if (TextUtils.isEmpty(str)) { - str = ""; - } - - return str; - } - - /** - * Use this method to determine if a given text has any HTML tag - * - * @param str String to be tested for presence of HTML content - * @return True if text contains any HTML tags
False is no HTML tag is found - */ - private static boolean isHtml(String str) { - final String htmlTagPattern = "<(\"[^\"]*\"|'[^']*'|[^'\">])*>"; - return Pattern.compile(htmlTagPattern).matcher(str).find(); - } - - /** - * Format an Element to plain-text - * @param element the root element to format - * @return formatted text - */ - public String getPlainText(Element element) { - FormattingVisitor formatter = new FormattingVisitor(); - // walk the DOM, and call .head() and .tail() for each node - NodeTraversor.traverse(formatter, element); - - return formatter.toString(); - } - - // the formatting rules, implemented in a breadth-first DOM traverse - private static class FormattingVisitor implements NodeVisitor { - - private final StringBuilder accum = new StringBuilder(); // holds the accumulated text - - // hit when the node is first seen - public void head(Node node, int depth) { - String name = node.nodeName(); - if (node instanceof TextNode) { - append(((TextNode) node).text()); // TextNodes carry all user-readable text in the DOM. - } else if (name.equals("li")) { - append("\n * "); - } else if (name.equals("dt")) { - append(" "); - } else if (StringUtil.in(name, "p", "h1", "h2", "h3", "h4", "h5", "tr")) { - append("\n"); - } - } - - // hit when all of the node's children (if any) have been visited - public void tail(Node node, int depth) { - String name = node.nodeName(); - if (StringUtil.in(name, "br", "dd", "dt", "p", "h1", "h2", "h3", "h4", "h5")) { - append("\n"); - } else if (name.equals("a")) { - append(String.format(" <%s>", node.absUrl("href"))); - } - } - - // appends text to the string builder with a simple word wrap method - private void append(String text) { - if (text.equals(" ") && - (accum.length() == 0 || StringUtil.in(accum.substring(accum.length() - 1), " ", "\n"))) { - return; // don't accumulate long runs of empty spaces - } - - accum.append(text); - } - - @Override - public String toString() { - return accum.toString(); - } - } -} diff --git a/core/src/test/java/android/text/TextUtils.java b/core/src/test/java/android/text/TextUtils.java deleted file mode 100644 index 709cb9e93..000000000 --- a/core/src/test/java/android/text/TextUtils.java +++ /dev/null @@ -1,42 +0,0 @@ -package android.text; - -/** - * A slim-down version of standard {@link android.text.TextUtils} to be used in unit tests. - */ -public class TextUtils { - - /** - * Returns true if a and b are equal, including if they are both null. - *

Note: In platform versions 1.1 and earlier, this method only worked well if - * both the arguments were instances of String.

- * @param a first CharSequence to check - * @param b second CharSequence to check - * @return true if a and b are equal - */ - @SuppressWarnings("unused") - public static boolean equals(CharSequence a, CharSequence b) { - if (a == b) return true; - int length; - if (a != null && b != null && (length = a.length()) == b.length()) { - if (a instanceof String && b instanceof String) { - return a.equals(b); - } else { - for (int i = 0; i < length; i++) { - if (a.charAt(i) != b.charAt(i)) return false; - } - return true; - } - } - return false; - } - - /** - * Returns true if the string is null or has zero length. - * - * @param str The string to be examined, can be null. - * @return true if the string is null or has zero length. - */ - public static boolean isEmpty(CharSequence str) { - return str == null || str.length() == 0; - } -} diff --git a/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java b/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java deleted file mode 100644 index 966351a5e..000000000 --- a/core/src/test/java/de/danoeh/antennapod/core/feed/VolumeAdaptionSettingTest.java +++ /dev/null @@ -1,129 +0,0 @@ -package de.danoeh.antennapod.core.feed; - -import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertTrue; - -public class VolumeAdaptionSettingTest { - - @Before - public void setUp() throws Exception { - VolumeAdaptionSetting.setBoostSupported(false); - } - - @After - public void tearDown() throws Exception { - VolumeAdaptionSetting.setBoostSupported(null); - } - - @Test - public void mapOffToInteger() { - VolumeAdaptionSetting setting = VolumeAdaptionSetting.OFF; - assertThat(setting.toInteger(), is(equalTo(0))); - } - - @Test - public void mapLightReductionToInteger() { - VolumeAdaptionSetting setting = VolumeAdaptionSetting.LIGHT_REDUCTION; - - assertThat(setting.toInteger(), is(equalTo(1))); - } - - @Test - public void mapHeavyReductionToInteger() { - VolumeAdaptionSetting setting = VolumeAdaptionSetting.HEAVY_REDUCTION; - - assertThat(setting.toInteger(), is(equalTo(2))); - } - - @Test - public void mapLightBoostToInteger() { - VolumeAdaptionSetting setting = VolumeAdaptionSetting.LIGHT_BOOST; - - assertThat(setting.toInteger(), is(equalTo(3))); - } - - @Test - public void mapMediumBoostToInteger() { - VolumeAdaptionSetting setting = VolumeAdaptionSetting.MEDIUM_BOOST; - - assertThat(setting.toInteger(), is(equalTo(4))); - } - - @Test - public void mapHeavyBoostToInteger() { - VolumeAdaptionSetting setting = VolumeAdaptionSetting.HEAVY_BOOST; - - assertThat(setting.toInteger(), is(equalTo(5))); - } - - @Test - public void mapIntegerToVolumeAdaptionSetting() { - assertThat(VolumeAdaptionSetting.fromInteger(0), is(equalTo(VolumeAdaptionSetting.OFF))); - assertThat(VolumeAdaptionSetting.fromInteger(1), is(equalTo(VolumeAdaptionSetting.LIGHT_REDUCTION))); - assertThat(VolumeAdaptionSetting.fromInteger(2), is(equalTo(VolumeAdaptionSetting.HEAVY_REDUCTION))); - assertThat(VolumeAdaptionSetting.fromInteger(3), is(equalTo(VolumeAdaptionSetting.LIGHT_BOOST))); - assertThat(VolumeAdaptionSetting.fromInteger(4), is(equalTo(VolumeAdaptionSetting.MEDIUM_BOOST))); - assertThat(VolumeAdaptionSetting.fromInteger(5), is(equalTo(VolumeAdaptionSetting.HEAVY_BOOST))); - } - - @Test(expected = IllegalArgumentException.class) - public void cannotMapNegativeValues() { - VolumeAdaptionSetting.fromInteger(-1); - } - - @Test(expected = IllegalArgumentException.class) - public void cannotMapValuesOutOfRange() { - VolumeAdaptionSetting.fromInteger(6); - } - - @Test - public void noAdaptionIfTurnedOff() { - float adaptionFactor = VolumeAdaptionSetting.OFF.getAdaptionFactor(); - assertEquals(1.0f, adaptionFactor, 0.01f); - } - - @Test - public void lightReductionYieldsHigherValueThanHeavyReduction() { - float lightReductionFactor = VolumeAdaptionSetting.LIGHT_REDUCTION.getAdaptionFactor(); - - float heavyReductionFactor = VolumeAdaptionSetting.HEAVY_REDUCTION.getAdaptionFactor(); - - assertTrue("Light reduction must have higher factor than heavy reduction", lightReductionFactor > heavyReductionFactor); - } - - @Test - public void lightBoostYieldsHigherValueThanLightReduction() { - float lightReductionFactor = VolumeAdaptionSetting.LIGHT_REDUCTION.getAdaptionFactor(); - - float lightBoostFactor = VolumeAdaptionSetting.LIGHT_BOOST.getAdaptionFactor(); - - assertTrue("Light boost must have higher factor than light reduction", lightBoostFactor > lightReductionFactor); - } - - @Test - public void mediumBoostYieldsHigherValueThanLightBoost() { - float lightBoostFactor = VolumeAdaptionSetting.LIGHT_BOOST.getAdaptionFactor(); - - float mediumBoostFactor = VolumeAdaptionSetting.MEDIUM_BOOST.getAdaptionFactor(); - - assertTrue("Medium boost must have higher factor than light boost", mediumBoostFactor > lightBoostFactor); - } - - @Test - public void heavyBoostYieldsHigherValueThanMediumBoost() { - float mediumBoostFactor = VolumeAdaptionSetting.MEDIUM_BOOST.getAdaptionFactor(); - - float heavyBoostFactor = VolumeAdaptionSetting.HEAVY_BOOST.getAdaptionFactor(); - - assertTrue("Heavy boost must have higher factor than medium boost", heavyBoostFactor > mediumBoostFactor); - } -} diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java deleted file mode 100644 index 87ade0c6f..000000000 --- a/core/src/test/java/de/danoeh/antennapod/core/storage/mapper/FeedCursorMapperTest.java +++ /dev/null @@ -1,101 +0,0 @@ -package de.danoeh.antennapod.core.storage.mapper; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; - -import androidx.test.platform.app.InstrumentationRegistry; - -import de.danoeh.antennapod.storage.database.PodDBAdapter; -import de.danoeh.antennapod.storage.database.mapper.FeedCursorMapper; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -import de.danoeh.antennapod.model.feed.Feed; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -@RunWith(RobolectricTestRunner.class) -public class FeedCursorMapperTest { - private PodDBAdapter adapter; - - @Before - public void setUp() { - Context context = InstrumentationRegistry.getInstrumentation().getContext(); - - PodDBAdapter.init(context); - adapter = PodDBAdapter.getInstance(); - - writeFeedToDatabase(); - } - - @After - public void tearDown() { - PodDBAdapter.tearDownTests(); - } - - @SuppressWarnings("ConstantConditions") - @Test - public void testFromCursor() { - try (Cursor cursor = adapter.getAllFeedsCursor()) { - cursor.moveToNext(); - Feed feed = FeedCursorMapper.convert(cursor); - assertTrue(feed.getId() >= 0); - assertEquals("feed custom title", feed.getTitle()); - assertEquals("feed custom title", feed.getCustomTitle()); - assertEquals("feed link", feed.getLink()); - assertEquals("feed description", feed.getDescription()); - assertEquals("feed payment link", feed.getPaymentLinks().get(0).url); - assertEquals("feed author", feed.getAuthor()); - assertEquals("feed language", feed.getLanguage()); - assertEquals("feed image url", feed.getImageUrl()); - assertEquals("feed file url", feed.getLocalFileUrl()); - assertEquals("feed download url", feed.getDownloadUrl()); - assertEquals(42, feed.getLastRefreshAttempt()); - assertEquals("feed last update", feed.getLastModified()); - assertEquals("feed type", feed.getType()); - assertEquals("feed identifier", feed.getFeedIdentifier()); - assertTrue(feed.isPaged()); - assertEquals("feed next page link", feed.getNextPageLink()); - assertTrue(feed.getItemFilter().showUnplayed); - assertEquals(1, feed.getSortOrder().code); - assertTrue(feed.hasLastUpdateFailed()); - } - } - - /** - * Insert test data to the database. - * Uses raw database insert instead of adapter.setCompleteFeed() to avoid testing the Feed class - * against itself. - */ - private void writeFeedToDatabase() { - ContentValues values = new ContentValues(); - values.put(PodDBAdapter.KEY_TITLE, "feed title"); - values.put(PodDBAdapter.KEY_CUSTOM_TITLE, "feed custom title"); - values.put(PodDBAdapter.KEY_LINK, "feed link"); - values.put(PodDBAdapter.KEY_DESCRIPTION, "feed description"); - values.put(PodDBAdapter.KEY_PAYMENT_LINK, "feed payment link"); - values.put(PodDBAdapter.KEY_AUTHOR, "feed author"); - values.put(PodDBAdapter.KEY_LANGUAGE, "feed language"); - values.put(PodDBAdapter.KEY_IMAGE_URL, "feed image url"); - - values.put(PodDBAdapter.KEY_FILE_URL, "feed file url"); - values.put(PodDBAdapter.KEY_DOWNLOAD_URL, "feed download url"); - values.put(PodDBAdapter.KEY_LAST_REFRESH_ATTEMPT, 42); - values.put(PodDBAdapter.KEY_LASTUPDATE, "feed last update"); - values.put(PodDBAdapter.KEY_TYPE, "feed type"); - values.put(PodDBAdapter.KEY_FEED_IDENTIFIER, "feed identifier"); - - values.put(PodDBAdapter.KEY_IS_PAGED, true); - values.put(PodDBAdapter.KEY_NEXT_PAGE_LINK, "feed next page link"); - values.put(PodDBAdapter.KEY_HIDE, "unplayed"); - values.put(PodDBAdapter.KEY_SORT_ORDER, "1"); - values.put(PodDBAdapter.KEY_LAST_UPDATE_FAILED, true); - - adapter.insertTestData(PodDBAdapter.TABLE_NAME_FEEDS, values); - } -} diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/ConverterTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/ConverterTest.java deleted file mode 100644 index 2e4ead5e6..000000000 --- a/core/src/test/java/de/danoeh/antennapod/core/util/ConverterTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import de.danoeh.antennapod.ui.common.Converter; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -/** - * Test class for converter - */ -public class ConverterTest { - - @Test - public void testGetDurationStringLong() { - String expected = "13:05:10"; - int input = 47110000; - assertEquals(expected, Converter.getDurationStringLong(input)); - } - - @Test - public void testGetDurationStringShort() { - String expected = "13:05"; - assertEquals(expected, Converter.getDurationStringShort(47110000, true)); - assertEquals(expected, Converter.getDurationStringShort(785000, false)); - } - - @Test - public void testDurationStringLongToMs() { - String input = "01:20:30"; - long expected = 4830000; - assertEquals(expected, Converter.durationStringLongToMs(input)); - } - - @Test - public void testDurationStringShortToMs() { - String input = "8:30"; - assertEquals(30600000, Converter.durationStringShortToMs(input, true)); - assertEquals(510000, Converter.durationStringShortToMs(input, false)); - } -} diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemPermutorsTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemPermutorsTest.java deleted file mode 100644 index 4ebff066e..000000000 --- a/core/src/test/java/de/danoeh/antennapod/core/util/FeedItemPermutorsTest.java +++ /dev/null @@ -1,231 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import de.danoeh.antennapod.model.feed.SortOrder; -import de.danoeh.antennapod.storage.database.FeedItemPermutors; -import de.danoeh.antennapod.storage.database.Permutor; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; - -import de.danoeh.antennapod.model.feed.Feed; -import de.danoeh.antennapod.model.feed.FeedItem; -import de.danoeh.antennapod.model.feed.FeedMedia; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -/** - * Test class for FeedItemPermutors. - */ -public class FeedItemPermutorsTest { - - @Test - public void testEnsureNonNullPermutors() { - for (SortOrder sortOrder : SortOrder.values()) { - assertNotNull("The permutor for SortOrder " + sortOrder + " is unexpectedly null", - FeedItemPermutors.getPermutor(sortOrder)); - } - } - - @Test - public void testPermutorForRule_EPISODE_TITLE_ASC() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_A_Z); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting - } - - @Test - public void testPermutorForRule_EPISODE_TITLE_ASC_NullTitle() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_A_Z); - - List itemList = getTestList(); - itemList.get(2) // itemId 2 - .setTitle(null); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting - } - - - @Test - public void testPermutorForRule_EPISODE_TITLE_DESC() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_Z_A); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting - } - - @Test - public void testPermutorForRule_DATE_ASC() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_OLD_NEW); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting - } - - @Test - public void testPermutorForRule_DATE_ASC_NulPubDatel() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_OLD_NEW); - - List itemList = getTestList(); - itemList.get(2) // itemId 2 - .setPubDate(null); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting - } - - @Test - public void testPermutorForRule_DATE_DESC() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_NEW_OLD); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting - } - - @Test - public void testPermutorForRule_DURATION_ASC() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_SHORT_LONG); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting - } - - @Test - public void testPermutorForRule_DURATION_DESC() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_LONG_SHORT); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting - } - - @Test - public void testPermutorForRule_size_asc() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.SIZE_SMALL_LARGE); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting - } - - @Test - public void testPermutorForRule_size_desc() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.SIZE_LARGE_SMALL); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting - } - - @Test - public void testPermutorForRule_DURATION_DESC_NullMedia() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_LONG_SHORT); - - List itemList = getTestList(); - itemList.get(1) // itemId 3 - .setMedia(null); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting - } - - @Test - public void testPermutorForRule_FEED_TITLE_ASC() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_A_Z); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting - } - - @Test - public void testPermutorForRule_FEED_TITLE_DESC() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_Z_A); - - List itemList = getTestList(); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting - } - - @Test - public void testPermutorForRule_FEED_TITLE_DESC_NullTitle() { - Permutor permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_Z_A); - - List itemList = getTestList(); - itemList.get(1) // itemId 3 - .getFeed().setTitle(null); - assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting - permutor.reorder(itemList); - assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting - } - - /** - * Generates a list with test data. - */ - private List getTestList() { - List itemList = new ArrayList<>(); - - Calendar calendar = Calendar.getInstance(); - calendar.set(2019, 0, 1); // January 1st - Feed feed1 = new Feed(null, null, "Feed title 1"); - FeedItem feedItem1 = new FeedItem(1, "Title 1", null, null, calendar.getTime(), 0, feed1); - FeedMedia feedMedia1 = new FeedMedia(0, feedItem1, 1000, 0, 100, null, null, null, true, null, 0, 0); - feedItem1.setMedia(feedMedia1); - itemList.add(feedItem1); - - calendar.set(2019, 2, 1); // March 1st - Feed feed2 = new Feed(null, null, "Feed title 3"); - FeedItem feedItem2 = new FeedItem(3, "Title 3", null, null, calendar.getTime(), 0, feed2); - FeedMedia feedMedia2 = new FeedMedia(0, feedItem2, 3000, 0, 300, null, null, null, true, null, 0, 0); - feedItem2.setMedia(feedMedia2); - itemList.add(feedItem2); - - calendar.set(2019, 1, 1); // February 1st - Feed feed3 = new Feed(null, null, "Feed title 2"); - FeedItem feedItem3 = new FeedItem(2, "Title 2", null, null, calendar.getTime(), 0, feed3); - FeedMedia feedMedia3 = new FeedMedia(0, feedItem3, 2000, 0, 200, null, null, null, true, null, 0, 0); - feedItem3.setMedia(feedMedia3); - itemList.add(feedItem3); - - return itemList; - } - - /** - * Checks if both lists have the same size and the same ID order. - * - * @param itemList Item list. - * @param ids List of IDs. - * @return true if both lists have the same size and the same ID order. - */ - private boolean checkIdOrder(List itemList, long... ids) { - if (itemList.size() != ids.length) { - return false; - } - - for (int i = 0; i < ids.length; i++) { - if (itemList.get(i).getId() != ids[i]) { - return false; - } - } - return true; - } -} diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/FilenameGeneratorTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/FilenameGeneratorTest.java deleted file mode 100644 index 4c225322a..000000000 --- a/core/src/test/java/de/danoeh/antennapod/core/util/FilenameGeneratorTest.java +++ /dev/null @@ -1,99 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import androidx.test.platform.app.InstrumentationRegistry; -import android.text.TextUtils; - -import java.io.File; - -import de.danoeh.antennapod.net.download.serviceinterface.FileNameGenerator; -import org.apache.commons.lang3.StringUtils; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; - -@RunWith(RobolectricTestRunner.class) -public class FilenameGeneratorTest { - - public FilenameGeneratorTest() { - super(); - } - - @Test - public void testGenerateFileName() throws Exception { - String result = FileNameGenerator.generateFileName("abc abc"); - assertEquals(result, "abc abc"); - createFiles(result); - } - - @Test - public void testGenerateFileName1() throws Exception { - String result = FileNameGenerator.generateFileName("ab/c: "; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, Integer.MAX_VALUE); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAddTimecodeHhmmssMoreThen24HoursNoChapters() { - final String timeStr = "25:00:00"; - final long time = 25 * 60 * 60 * 1000; - - String shownotes = "

Some test text with a timecode " + timeStr + " here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, Integer.MAX_VALUE); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAddTimecodeHhmmNoChapters() { - final String timeStr = "10:11"; - final long time = 3600 * 1000 * 10 + 60 * 1000 * 11; - - String shownotes = "

Some test text with a timecode " + timeStr + " here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, Integer.MAX_VALUE); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAddTimecodeMmssNoChapters() { - final String timeStr = "10:11"; - final long time = 10 * 60 * 1000 + 11 * 1000; - - String shownotes = "

Some test text with a timecode " + timeStr + " here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, 11 * 60 * 1000); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAddTimecodeHmmssNoChapters() { - final String timeStr = "2:11:12"; - final long time = 2 * 60 * 60 * 1000 + 11 * 60 * 1000 + 12 * 1000; - - String shownotes = "

Some test text with a timecode " + timeStr + " here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, Integer.MAX_VALUE); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAddTimecodeMssNoChapters() { - final String timeStr = "1:12"; - final long time = 60 * 1000 + 12 * 1000; - - String shownotes = "

Some test text with a timecode " + timeStr + " here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, 2 * 60 * 1000); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAddNoTimecodeDuration() { - final String timeStr = "2:11:12"; - final int time = 2 * 60 * 60 * 1000 + 11 * 60 * 1000 + 12 * 1000; - - String shownotes = "

Some test text with a timecode " + timeStr + " here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, time); - String res = t.processShownotes(); - Document d = Jsoup.parse(res); - assertEquals("Should not parse time codes that equal duration", 0, d.body().getElementsByTag("a").size()); - } - - @Test - public void testProcessShownotesAddTimecodeMultipleFormatsNoChapters() { - final String[] timeStrings = new String[]{ "10:12", "1:10:12" }; - - String shownotes = "

Some test text with a timecode " + timeStrings[0] - + " here. Hey look another one " + timeStrings[1] + " here!

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, 2 * 60 * 60 * 1000); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{10 * 60 * 1000 + 12 * 1000, - 60 * 60 * 1000 + 10 * 60 * 1000 + 12 * 1000}, timeStrings); - } - - @Test - public void testProcessShownotesAddTimecodeMultipleShortFormatNoChapters() { - - // One of these timecodes fits as HH:MM and one does not so both should be parsed as MM:SS. - final String[] timeStrings = new String[]{ "10:12", "2:12" }; - - String shownotes = "

Some test text with a timecode " + timeStrings[0] - + " here. Hey look another one " + timeStrings[1] + " here!

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, 3 * 60 * 60 * 1000); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{10 * 60 * 1000 + 12 * 1000, 2 * 60 * 1000 + 12 * 1000}, timeStrings); - } - - @Test - public void testProcessShownotesAddTimecodeParentheses() { - final String timeStr = "10:11"; - final long time = 3600 * 1000 * 10 + 60 * 1000 * 11; - - String shownotes = "

Some test text with a timecode (" + timeStr + ") here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, Integer.MAX_VALUE); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAddTimecodeBrackets() { - final String timeStr = "10:11"; - final long time = 3600 * 1000 * 10 + 60 * 1000 * 11; - - String shownotes = "

Some test text with a timecode [" + timeStr + "] here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, Integer.MAX_VALUE); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAddTimecodeAngleBrackets() { - final String timeStr = "10:11"; - final long time = 3600 * 1000 * 10 + 60 * 1000 * 11; - - String shownotes = "

Some test text with a timecode <" + timeStr + "> here.

"; - ShownotesCleaner t = new ShownotesCleaner(context, shownotes, Integer.MAX_VALUE); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[]{time}, new String[]{timeStr}); - } - - @Test - public void testProcessShownotesAndInvalidTimecode() { - final String[] timeStrs = new String[] {"2:1", "0:0", "000", "00", "00:000"}; - - StringBuilder shownotes = new StringBuilder("

Some test text with timecodes "); - for (String timeStr : timeStrs) { - shownotes.append(timeStr).append(" "); - } - shownotes.append("here.

"); - - ShownotesCleaner t = new ShownotesCleaner(context, shownotes.toString(), Integer.MAX_VALUE); - String res = t.processShownotes(); - checkLinkCorrect(res, new long[0], new String[0]); - } - - private void checkLinkCorrect(String res, long[] timecodes, String[] timecodeStr) { - assertNotNull(res); - Document d = Jsoup.parse(res); - Elements links = d.body().getElementsByTag("a"); - int countedLinks = 0; - for (Element link : links) { - String href = link.attributes().get("href"); - String text = link.text(); - if (href.startsWith("antennapod://")) { - assertTrue(href.endsWith(String.valueOf(timecodes[countedLinks]))); - assertEquals(timecodeStr[countedLinks], text); - countedLinks++; - assertTrue("Contains too many links: " + countedLinks + " > " - + timecodes.length, countedLinks <= timecodes.length); - } - } - assertEquals(timecodes.length, countedLinks); - } - - @Test - public void testIsTimecodeLink() { - assertFalse(ShownotesCleaner.isTimecodeLink(null)); - assertFalse(ShownotesCleaner.isTimecodeLink("http://antennapod/timecode/123123")); - assertFalse(ShownotesCleaner.isTimecodeLink("antennapod://timecode/")); - assertFalse(ShownotesCleaner.isTimecodeLink("antennapod://123123")); - assertFalse(ShownotesCleaner.isTimecodeLink("antennapod://timecode/123123a")); - assertTrue(ShownotesCleaner.isTimecodeLink("antennapod://timecode/123")); - assertTrue(ShownotesCleaner.isTimecodeLink("antennapod://timecode/1")); - } - - @Test - public void testGetTimecodeLinkTime() { - assertEquals(-1, ShownotesCleaner.getTimecodeLinkTime(null)); - assertEquals(-1, ShownotesCleaner.getTimecodeLinkTime("http://timecode/123")); - assertEquals(123, ShownotesCleaner.getTimecodeLinkTime("antennapod://timecode/123")); - } - - @Test - public void testCleanupColors() { - final String input = "/* /* */ .foo { text-decoration: underline;color:#f00;font-weight:bold;}" - + "#bar { text-decoration: underline;color:#f00;font-weight:bold; }" - + "div {text-decoration: underline; color /* */ : /* */ #f00 /* */; font-weight:bold; }" - + "#foobar { /* color: */ text-decoration: underline; /* color: */font-weight:bold /* ; */; }" - + "baz { background-color:#f00;border: solid 2px;border-color:#0f0;text-decoration: underline; }"; - final String expected = " .foo { text-decoration: underline;font-weight:bold;}" - + "#bar { text-decoration: underline;font-weight:bold; }" - + "div {text-decoration: underline; font-weight:bold; }" - + "#foobar { text-decoration: underline; font-weight:bold ; }" - + "baz { background-color:#f00;border: solid 2px;border-color:#0f0;text-decoration: underline; }"; - assertEquals(expected, ShownotesCleaner.cleanStyleTag(input)); - } -} diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/syndication/FeedDiscovererTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/syndication/FeedDiscovererTest.java deleted file mode 100644 index 3df5230cc..000000000 --- a/core/src/test/java/de/danoeh/antennapod/core/util/syndication/FeedDiscovererTest.java +++ /dev/null @@ -1,128 +0,0 @@ -package de.danoeh.antennapod.core.util.syndication; - -import androidx.test.platform.app.InstrumentationRegistry; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -import java.io.File; -import java.io.FileOutputStream; -import java.nio.charset.StandardCharsets; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -/** - * Test class for {@link FeedDiscoverer} - */ -@RunWith(RobolectricTestRunner.class) -public class FeedDiscovererTest { - - private FeedDiscoverer fd; - - private File testDir; - - @Before - public void setUp() { - fd = new FeedDiscoverer(); - testDir = new File(InstrumentationRegistry - .getInstrumentation().getTargetContext().getFilesDir(), "FeedDiscovererTest"); - //noinspection ResultOfMethodCallIgnored - testDir.mkdir(); - assertTrue(testDir.exists()); - } - - @After - public void tearDown() throws Exception { - FileUtils.deleteDirectory(testDir); - } - - @SuppressWarnings("SameParameterValue") - private String createTestHtmlString(String rel, String type, String href, String title) { - return String.format("Test", - rel, type, href, title); - } - - private String createTestHtmlString(String rel, String type, String href) { - return String.format("Test", - rel, type, href); - } - - private void checkFindUrls(boolean isAlternate, boolean isRss, boolean withTitle, boolean isAbsolute, boolean fromString) throws Exception { - final String title = "Test title"; - final String hrefAbs = "http://example.com/feed"; - final String hrefRel = "/feed"; - final String base = "http://example.com"; - - final String rel = (isAlternate) ? "alternate" : "feed"; - final String type = (isRss) ? "application/rss+xml" : "application/atom+xml"; - final String href = (isAbsolute) ? hrefAbs : hrefRel; - - Map res; - String html = (withTitle) ? createTestHtmlString(rel, type, href, title) - : createTestHtmlString(rel, type, href); - if (fromString) { - res = fd.findLinks(html, base); - } else { - File testFile = new File(testDir, "feed"); - FileOutputStream out = new FileOutputStream(testFile); - IOUtils.write(html, out, StandardCharsets.UTF_8); - out.close(); - res = fd.findLinks(testFile, base); - } - - assertNotNull(res); - assertEquals(1, res.size()); - for (String key : res.keySet()) { - assertEquals(hrefAbs, key); - } - assertTrue(res.containsKey(hrefAbs)); - if (withTitle) { - assertEquals(title, res.get(hrefAbs)); - } else { - assertEquals(href, res.get(hrefAbs)); - } - } - - @Test - public void testAlternateRSSWithTitleAbsolute() throws Exception { - checkFindUrls(true, true, true, true, true); - } - - @Test - public void testAlternateRSSWithTitleRelative() throws Exception { - checkFindUrls(true, true, true, false, true); - } - - @Test - public void testAlternateRSSNoTitleAbsolute() throws Exception { - checkFindUrls(true, true, false, true, true); - } - - @Test - public void testAlternateRSSNoTitleRelative() throws Exception { - checkFindUrls(true, true, false, false, true); - } - - @Test - public void testAlternateAtomWithTitleAbsolute() throws Exception { - checkFindUrls(true, false, true, true, true); - } - - @Test - public void testFeedAtomWithTitleAbsolute() throws Exception { - checkFindUrls(false, false, true, true, true); - } - - @Test - public void testAlternateRSSWithTitleAbsoluteFromFile() throws Exception { - checkFindUrls(true, true, true, true, false); - } -} -- cgit v1.2.3