diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java index 902cad98c..ef5719d6f 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java @@ -10,6 +10,7 @@ import androidx.test.espresso.matcher.RootMatchers; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; +import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithmFactory; import org.awaitility.Awaitility; import org.junit.Before; import org.junit.Rule; @@ -397,7 +398,7 @@ public class PreferencesTest { onView(withId(R.id.select_dialog_listview)).perform(swipeDown()); onView(withText(R.string.episode_cleanup_except_favorite_removal)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) - .until(() -> UserPreferences.getEpisodeCleanupAlgorithm() instanceof ExceptFavoriteCleanupAlgorithm); + .until(() -> EpisodeCleanupAlgorithmFactory.build() instanceof ExceptFavoriteCleanupAlgorithm); } @Test @@ -408,7 +409,7 @@ public class PreferencesTest { onView(withId(R.id.select_dialog_listview)).perform(swipeDown()); onView(withText(R.string.episode_cleanup_queue_removal)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) - .until(() -> UserPreferences.getEpisodeCleanupAlgorithm() instanceof APQueueCleanupAlgorithm); + .until(() -> EpisodeCleanupAlgorithmFactory.build() instanceof APQueueCleanupAlgorithm); } @Test @@ -419,7 +420,7 @@ public class PreferencesTest { onView(withId(R.id.select_dialog_listview)).perform(swipeUp()); onView(withText(R.string.episode_cleanup_never)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) - .until(() -> UserPreferences.getEpisodeCleanupAlgorithm() instanceof APNullCleanupAlgorithm); + .until(() -> EpisodeCleanupAlgorithmFactory.build() instanceof APNullCleanupAlgorithm); } @Test @@ -431,7 +432,7 @@ public class PreferencesTest { onView(withText(R.string.episode_cleanup_after_listening)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) .until(() -> { - EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm(); + EpisodeCleanupAlgorithm alg = EpisodeCleanupAlgorithmFactory.build(); if (alg instanceof APCleanupAlgorithm) { APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm) alg; return cleanupAlg.getNumberOfHoursAfterPlayback() == 0; @@ -450,7 +451,7 @@ public class PreferencesTest { onView(withText(search)).perform(click()); Awaitility.await().atMost(1000, MILLISECONDS) .until(() -> { - EpisodeCleanupAlgorithm alg = UserPreferences.getEpisodeCleanupAlgorithm(); + EpisodeCleanupAlgorithm alg = EpisodeCleanupAlgorithmFactory.build(); if (alg instanceof APCleanupAlgorithm) { APCleanupAlgorithm cleanupAlg = (APCleanupAlgorithm) alg; return cleanupAlg.getNumberOfHoursAfterPlayback() == 72; // 5 days diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java index 3f7a5db68..b23e22c9f 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -231,6 +231,7 @@ public class MainActivity extends CastEnabledActivity { // for backward compatibility, we only change defaults for fresh installs UserPreferences.setUpdateInterval(12); + AutoUpdateManager.restartUpdateAlarm(this); SharedPreferences.Editor edit = prefs.edit(); edit.putBoolean(PREF_IS_FIRST_LAUNCH, false); diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FeedRefreshIntervalDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FeedRefreshIntervalDialog.java index 7e42302d1..f97940f8b 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/FeedRefreshIntervalDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/FeedRefreshIntervalDialog.java @@ -10,6 +10,7 @@ import android.widget.ArrayAdapter; import androidx.appcompat.app.AlertDialog; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import de.danoeh.antennapod.databinding.FeedRefreshDialogBinding; import org.apache.commons.lang3.ArrayUtils; @@ -70,6 +71,7 @@ public class FeedRefreshIntervalDialog { builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { if (viewBinding.intervalRadioButton.isChecked()) { UserPreferences.setUpdateInterval(INTERVAL_VALUES_HOURS[viewBinding.spinner.getSelectedItemPosition()]); + AutoUpdateManager.restartUpdateAlarm(context); } else if (viewBinding.timeRadioButton.isChecked()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { UserPreferences.setUpdateTimeOfDay(viewBinding.timePicker.getHour(), @@ -78,8 +80,10 @@ public class FeedRefreshIntervalDialog { UserPreferences.setUpdateTimeOfDay(viewBinding.timePicker.getCurrentHour(), viewBinding.timePicker.getCurrentMinute()); } + AutoUpdateManager.restartUpdateAlarm(context); } else if (viewBinding.disableRadioButton.isChecked()) { - UserPreferences.disableAutoUpdate(context); + UserPreferences.disableAutoUpdate(); + AutoUpdateManager.disableAutoUpdate(context); } else { throw new IllegalStateException("Unexpected error."); } diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java index 2c3c44b1d..b24a26602 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java @@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; -import de.danoeh.antennapod.core.service.download.ProxyConfig; +import de.danoeh.antennapod.model.download.ProxyConfig; import io.reactivex.Completable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java index 9e524188f..a468794cb 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/SubscriptionsFilterDialog.java @@ -17,7 +17,7 @@ import java.util.Set; import de.danoeh.antennapod.R; import de.danoeh.antennapod.event.UnreadItemsUpdateEvent; -import de.danoeh.antennapod.core.feed.SubscriptionsFilter; +import de.danoeh.antennapod.model.feed.SubscriptionsFilter; import de.danoeh.antennapod.core.feed.SubscriptionsFilterGroup; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.ui.common.RecursiveRadioGroup; 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 081b7d5f0..b1bc38ebc 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 @@ -14,7 +14,6 @@ import androidx.annotation.VisibleForTesting; import androidx.core.app.NotificationCompat; import androidx.preference.PreferenceManager; -import de.danoeh.antennapod.model.feed.FeedCounter; import org.json.JSONArray; import org.json.JSONException; @@ -32,16 +31,11 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.R; +import de.danoeh.antennapod.model.feed.FeedCounter; import de.danoeh.antennapod.model.playback.MediaType; -import de.danoeh.antennapod.core.feed.SubscriptionsFilter; -import de.danoeh.antennapod.core.service.download.ProxyConfig; -import de.danoeh.antennapod.core.storage.APCleanupAlgorithm; -import de.danoeh.antennapod.core.storage.ExceptFavoriteCleanupAlgorithm; -import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm; -import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm; -import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm; +import de.danoeh.antennapod.model.feed.SubscriptionsFilter; +import de.danoeh.antennapod.model.download.ProxyConfig; import de.danoeh.antennapod.model.feed.SortOrder; -import de.danoeh.antennapod.core.util.download.AutoUpdateManager; /** * Provides access to preferences set by the user in the settings screen. A @@ -692,33 +686,22 @@ public class UserPreferences { .apply(); } - /** - * Sets the update interval value. - */ public static void setUpdateInterval(long hours) { prefs.edit() .putString(PREF_UPDATE_INTERVAL, String.valueOf(hours)) .apply(); - // when updating with an interval, we assume the user wants - // to update *now* and then every 'hours' interval thereafter. - AutoUpdateManager.restartUpdateAlarm(context); } - /** - * Sets the update interval value. - */ public static void setUpdateTimeOfDay(int hourOfDay, int minute) { prefs.edit() .putString(PREF_UPDATE_INTERVAL, hourOfDay + ":" + minute) .apply(); - AutoUpdateManager.restartUpdateAlarm(context); } - public static void disableAutoUpdate(Context context) { + public static void disableAutoUpdate() { prefs.edit() .putString(PREF_UPDATE_INTERVAL, "0") .apply(); - AutoUpdateManager.disableAutoUpdate(context); } public static boolean gpodnetNotificationsEnabled() { @@ -835,22 +818,6 @@ public class UserPreferences { .apply(); } - public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() { - if (!isEnableAutodownload()) { - return new APNullCleanupAlgorithm(); - } - int cleanupValue = getEpisodeCleanupValue(); - if (cleanupValue == EPISODE_CLEANUP_EXCEPT_FAVORITE) { - return new ExceptFavoriteCleanupAlgorithm(); - } else if (cleanupValue == EPISODE_CLEANUP_QUEUE) { - return new APQueueCleanupAlgorithm(); - } else if (cleanupValue == EPISODE_CLEANUP_NULL) { - return new APNullCleanupAlgorithm(); - } else { - return new APCleanupAlgorithm(cleanupValue); - } - } - public static int getEpisodeCleanupValue() { return Integer.parseInt(prefs.getString(PREF_EPISODE_CLEANUP, "" + EPISODE_CLEANUP_NULL)); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java index b1138eeff..9974fae51 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java @@ -6,6 +6,7 @@ import androidx.annotation.NonNull; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.BasicAuthorizationInterceptor; import de.danoeh.antennapod.core.service.UserAgentInterceptor; +import de.danoeh.antennapod.model.download.ProxyConfig; import de.danoeh.antennapod.net.ssl.SslClientSetup; import okhttp3.Cache; import okhttp3.Credentials; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index 1cd456072..40cc5f3f3 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -20,6 +20,7 @@ import androidx.core.app.ServiceCompat; import androidx.core.content.ContextCompat; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.feed.LocalFeedUpdater; +import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithmFactory; import de.danoeh.antennapod.model.download.DownloadStatus; import org.apache.commons.io.FileUtils; import org.greenrobot.eventbus.EventBus; @@ -455,7 +456,7 @@ public class DownloadService extends Service { Log.d(TAG, "Received enqueue request. #requests=" + requests.size()); if (intent.getBooleanExtra(EXTRA_CLEANUP_MEDIA, false)) { - UserPreferences.getEpisodeCleanupAlgorithm().makeRoomForEpisodes(getApplicationContext(), requests.size()); + EpisodeCleanupAlgorithmFactory.build().makeRoomForEpisodes(getApplicationContext(), requests.size()); } for (DownloadRequest request : requests) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/NewEpisodesNotification.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/NewEpisodesNotification.java index 0e046978e..8f955e3c5 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/NewEpisodesNotification.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/NewEpisodesNotification.java @@ -20,15 +20,16 @@ import de.danoeh.antennapod.model.feed.Feed; import de.danoeh.antennapod.model.feed.FeedCounter; import de.danoeh.antennapod.model.feed.FeedPreferences; import de.danoeh.antennapod.core.glide.ApGlideSettings; -import de.danoeh.antennapod.storage.database.LongIntMap; import de.danoeh.antennapod.core.util.gui.NotificationUtils; import de.danoeh.antennapod.storage.database.PodDBAdapter; +import java.util.Map; + public class NewEpisodesNotification { private static final String TAG = "NewEpisodesNotification"; private static final String GROUP_KEY = "de.danoeh.antennapod.EPISODES"; - private LongIntMap countersBefore; + private Map countersBefore; public NewEpisodesNotification() { } @@ -46,7 +47,7 @@ public class NewEpisodesNotification { return; } - int newEpisodesBefore = countersBefore.get(feed.getId()); + int newEpisodesBefore = countersBefore.containsKey(feed.getId()) ? countersBefore.get(feed.getId()) : 0; int newEpisodesAfter = getNewEpisodeCount(feed.getId()); Log.d(TAG, "New episodes before: " + newEpisodesBefore + ", after: " + newEpisodesAfter); @@ -130,7 +131,8 @@ public class NewEpisodesNotification { private static int getNewEpisodeCount(long feedId) { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - int episodeCount = adapter.getFeedCounters(FeedCounter.SHOW_NEW, feedId).get(feedId); + Map counters = adapter.getFeedCounters(FeedCounter.SHOW_NEW, feedId); + int episodeCount = counters.containsKey(feedId) ? counters.get(feedId) : 0; adapter.close(); return episodeCount; } 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 52638ca77..c410376c2 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 @@ -76,7 +76,7 @@ public class AutomaticDownloadAlgorithm { int autoDownloadableEpisodes = candidates.size(); int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes(); - int deletedEpisodes = UserPreferences.getEpisodeCleanupAlgorithm() + int deletedEpisodes = EpisodeCleanupAlgorithmFactory.build() .makeRoomForEpisodes(context, autoDownloadableEpisodes); boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences.getEpisodeCacheSizeUnlimited(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 528ded708..62a461dfe 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -21,7 +21,7 @@ import de.danoeh.antennapod.model.feed.FeedItem; import de.danoeh.antennapod.model.feed.FeedItemFilter; import de.danoeh.antennapod.model.feed.FeedMedia; import de.danoeh.antennapod.model.feed.FeedPreferences; -import de.danoeh.antennapod.core.feed.SubscriptionsFilter; +import de.danoeh.antennapod.model.feed.SubscriptionsFilter; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.model.download.DownloadStatus; import de.danoeh.antennapod.storage.database.PodDBAdapter; @@ -31,7 +31,6 @@ import de.danoeh.antennapod.storage.database.mapper.FeedCursorMapper; import de.danoeh.antennapod.storage.database.mapper.FeedItemCursorMapper; import de.danoeh.antennapod.storage.database.mapper.FeedMediaCursorMapper; import de.danoeh.antennapod.storage.database.mapper.FeedPreferencesCursorMapper; -import de.danoeh.antennapod.storage.database.LongIntMap; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.comparator.DownloadStatusComparator; import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator; @@ -881,7 +880,7 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - final LongIntMap feedCounters = adapter.getFeedCounters(UserPreferences.getFeedCounterSetting()); + final Map feedCounters = adapter.getFeedCounters(UserPreferences.getFeedCounterSetting()); SubscriptionsFilter subscriptionsFilter = UserPreferences.getSubscriptionsFilter(); List feeds = subscriptionsFilter.filter(getFeedList(adapter), feedCounters); @@ -889,8 +888,8 @@ public final class DBReader { int feedOrder = UserPreferences.getFeedOrder(); if (feedOrder == UserPreferences.FEED_ORDER_COUNTER) { comparator = (lhs, rhs) -> { - long counterLhs = feedCounters.get(lhs.getId()); - long counterRhs = feedCounters.get(rhs.getId()); + long counterLhs = feedCounters.containsKey(lhs.getId()) ? feedCounters.get(lhs.getId()) : 0; + long counterRhs = feedCounters.containsKey(rhs.getId()) ? feedCounters.get(rhs.getId()) : 0; if (counterLhs > counterRhs) { // reverse natural order: podcast with most unplayed episodes first return -1; @@ -913,11 +912,11 @@ public final class DBReader { } }; } else if (feedOrder == UserPreferences.FEED_ORDER_MOST_PLAYED) { - final LongIntMap playedCounters = adapter.getPlayedEpisodesCounters(); + final Map playedCounters = adapter.getPlayedEpisodesCounters(); comparator = (lhs, rhs) -> { - long counterLhs = playedCounters.get(lhs.getId()); - long counterRhs = playedCounters.get(rhs.getId()); + long counterLhs = playedCounters.containsKey(lhs.getId()) ? playedCounters.get(lhs.getId()) : 0; + long counterRhs = playedCounters.containsKey(rhs.getId()) ? playedCounters.get(rhs.getId()) : 0; if (counterLhs > counterRhs) { // podcast with most played episodes first return -1; @@ -945,8 +944,8 @@ public final class DBReader { Map folders = new HashMap<>(); for (Feed feed : feeds) { for (String tag : feed.getPreferences().getTags()) { - NavDrawerData.FeedDrawerItem drawerItem = new NavDrawerData.FeedDrawerItem(feed, feed.getId(), - feedCounters.get(feed.getId())); + int counter = feedCounters.containsKey(feed.getId()) ? feedCounters.get(feed.getId()) : 0; + NavDrawerData.FeedDrawerItem drawerItem = new NavDrawerData.FeedDrawerItem(feed, feed.getId(), counter); if (FeedPreferences.TAG_ROOT.equals(tag)) { items.add(drawerItem); continue; @@ -967,7 +966,7 @@ public final class DBReader { items.addAll(foldersSorted); NavDrawerData result = new NavDrawerData(items, queueSize, numNewItems, numDownloadedItems, - feedCounters, UserPreferences.getEpisodeCleanupAlgorithm().getReclaimableItems()); + feedCounters, EpisodeCleanupAlgorithmFactory.build().getReclaimableItems()); adapter.close(); return result; } 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 6ec27c01e..e9fe3af1a 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 @@ -228,7 +228,7 @@ public final class DBTasks { * @param context Used for accessing the DB. */ public static void performAutoCleanup(final Context context) { - UserPreferences.getEpisodeCleanupAlgorithm().performCleanup(context); + EpisodeCleanupAlgorithmFactory.build().performCleanup(context); } private static Feed searchFeedByIdentifyingValueOrID(Feed feed) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithmFactory.java b/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithmFactory.java new file mode 100644 index 000000000..123ccba3f --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithmFactory.java @@ -0,0 +1,22 @@ +package de.danoeh.antennapod.core.storage; + +import de.danoeh.antennapod.core.preferences.UserPreferences; + +public abstract class EpisodeCleanupAlgorithmFactory { + public static EpisodeCleanupAlgorithm build() { + if (!UserPreferences.isEnableAutodownload()) { + return new APNullCleanupAlgorithm(); + } + int cleanupValue = UserPreferences.getEpisodeCleanupValue(); + switch (cleanupValue) { + case UserPreferences.EPISODE_CLEANUP_EXCEPT_FAVORITE: + return new ExceptFavoriteCleanupAlgorithm(); + case UserPreferences.EPISODE_CLEANUP_QUEUE: + return new APQueueCleanupAlgorithm(); + case UserPreferences.EPISODE_CLEANUP_NULL: + return new APNullCleanupAlgorithm(); + default: + return new APCleanupAlgorithm(cleanupValue); + } + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java b/core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java index 24b55f9f4..af02a7733 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/NavDrawerData.java @@ -1,24 +1,24 @@ package de.danoeh.antennapod.core.storage; import de.danoeh.antennapod.model.feed.Feed; -import de.danoeh.antennapod.storage.database.LongIntMap; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class NavDrawerData { public final List items; public final int queueSize; public final int numNewItems; public final int numDownloadedItems; - public final LongIntMap feedCounters; + public final Map feedCounters; public final int reclaimableSpace; public NavDrawerData(List feeds, int queueSize, int numNewItems, int numDownloadedItems, - LongIntMap feedIndicatorValues, + Map feedIndicatorValues, int reclaimableSpace) { this.items = feeds; this.queueSize = queueSize; diff --git a/core/src/test/java/de/danoeh/antennapod/core/util/LongLongMapTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/LongLongMapTest.java deleted file mode 100644 index 03326d3b1..000000000 --- a/core/src/test/java/de/danoeh/antennapod/core/util/LongLongMapTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package de.danoeh.antennapod.core.util; - -import de.danoeh.antennapod.storage.database.LongIntMap; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class LongLongMapTest { - - @Test - public void testEmptyMap() { - LongIntMap map = new LongIntMap(); - assertEquals(0, map.size()); - assertEquals("LongLongMap{}", map.toString()); - assertEquals(0, map.get(42)); - assertEquals(-1, map.get(42, -1)); - assertFalse(map.delete(42)); - assertEquals(-1, map.indexOfKey(42)); - assertEquals(-1, map.indexOfValue(42)); - assertEquals(1, map.hashCode()); - } - - @Test - public void testSingleElement() { - LongIntMap map = new LongIntMap(); - map.put(17, 42); - assertEquals(1, map.size()); - assertEquals("LongLongMap{17=42}", map.toString()); - assertEquals(42, map.get(17)); - assertEquals(42, map.get(17, -1)); - assertEquals(0, map.indexOfKey(17)); - assertEquals(0, map.indexOfValue(42)); - assertTrue(map.delete(17)); - } - - @Test - public void testAddAndDelete() { - LongIntMap map = new LongIntMap(); - for(int i=0; i < 100; i++) { - map.put(i * 17, i * 42); - } - assertEquals(100, map.size()); - assertEquals(0, map.get(0)); - assertEquals(42, map.get(17)); - assertEquals(42, map.get(17, -1)); - assertEquals(1, map.indexOfKey(17)); - assertEquals(1, map.indexOfValue(42)); - for(int i=0; i < 100; i++) { - assertTrue(map.delete(i * 17)); - } - } - - @Test - public void testOverwrite() { - LongIntMap map = new LongIntMap(); - map.put(17, 42); - assertEquals(1, map.size()); - assertEquals("LongLongMap{17=42}", map.toString()); - assertEquals(42, map.get(17)); - map.put(17, 23); - assertEquals(1, map.size()); - assertEquals("LongLongMap{17=23}", map.toString()); - assertEquals(23, map.get(17)); - } - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java b/model/src/main/java/de/danoeh/antennapod/model/download/ProxyConfig.java similarity index 91% rename from core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java rename to model/src/main/java/de/danoeh/antennapod/model/download/ProxyConfig.java index 797001e3a..4e194b341 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java +++ b/model/src/main/java/de/danoeh/antennapod/model/download/ProxyConfig.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.core.service.download; +package de.danoeh.antennapod.model.download; import androidx.annotation.Nullable; diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/SubscriptionsFilter.java b/model/src/main/java/de/danoeh/antennapod/model/feed/SubscriptionsFilter.java similarity index 91% rename from core/src/main/java/de/danoeh/antennapod/core/feed/SubscriptionsFilter.java rename to model/src/main/java/de/danoeh/antennapod/model/feed/SubscriptionsFilter.java index 7e80fb231..434d474a7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/SubscriptionsFilter.java +++ b/model/src/main/java/de/danoeh/antennapod/model/feed/SubscriptionsFilter.java @@ -1,13 +1,10 @@ -package de.danoeh.antennapod.core.feed; +package de.danoeh.antennapod.model.feed; import android.text.TextUtils; import java.util.ArrayList; import java.util.List; - -import de.danoeh.antennapod.storage.database.LongIntMap; -import de.danoeh.antennapod.model.feed.Feed; -import de.danoeh.antennapod.model.feed.FeedPreferences; +import java.util.Map; public class SubscriptionsFilter { private static final String divider = ","; @@ -69,7 +66,7 @@ public class SubscriptionsFilter { /** * Run a list of feed items through the filter. */ - public List filter(List items, LongIntMap feedCounters) { + public List filter(List items, Map feedCounters) { if (properties.length == 0) { return items; } @@ -104,7 +101,8 @@ public class SubscriptionsFilter { if (showIfCounterGreaterZero) { for (int i = result.size() - 1; i >= 0; i--) { - if (feedCounters.get(result.get(i).getId()) <= 0) { + if (!feedCounters.containsKey(result.get(i).getId()) + || feedCounters.get(result.get(i).getId()) <= 0) { result.remove(i); } } diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/LongIntMap.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/LongIntMap.java deleted file mode 100644 index 049b24627..000000000 --- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/LongIntMap.java +++ /dev/null @@ -1,263 +0,0 @@ -package de.danoeh.antennapod.storage.database; - - -import java.util.Arrays; - -/** - * Fast and memory efficient long to long map - */ -public class LongIntMap { - - private long[] keys; - private int[] values; - private int size; - - /** - * Creates a new LongLongMap containing no mappings. - */ - public LongIntMap() { - this(10); - } - - /** - * Creates a new SparseLongArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. If you supply an initial capacity of 0, the - * sparse array will be initialized with a light-weight representation - * not requiring any additional array allocations. - */ - public LongIntMap(int initialCapacity) { - if(initialCapacity < 0) { - throw new IllegalArgumentException("initial capacity must be 0 or higher"); - } - keys = new long[initialCapacity]; - values = new int[initialCapacity]; - size = 0; - } - - /** - * Increases size of array if needed - */ - private void growIfNeeded() { - if (size == keys.length) { - // Resize. - long[] newKeysArray = new long[size * 3 / 2 + 10]; - int[] newValuesArray = new int[size * 3 / 2 + 10]; - System.arraycopy(keys, 0, newKeysArray, 0, size); - System.arraycopy(values, 0, newValuesArray, 0, size); - keys = newKeysArray; - values = newValuesArray; - } - } - - /** - * Gets the long mapped from the specified key, or 0 - * if no such mapping has been made. - */ - public int get(long key) { - return get(key, 0); - } - - /** - * Gets the long mapped from the specified key, or the specified value - * if no such mapping has been made. - */ - public int get(long key, int valueIfKeyNotFound) { - int index = indexOfKey(key); - if(index >= 0) { - return values[index]; - } else { - return valueIfKeyNotFound; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public boolean delete(long key) { - int index = indexOfKey(key); - - if (index >= 0) { - removeAt(index); - return true; - } else { - return false; - } - } - - /** - * Removes the mapping at the given index. - */ - private void removeAt(int index) { - System.arraycopy(keys, index + 1, keys, index, size - (index + 1)); - System.arraycopy(values, index + 1, values, index, size - (index + 1)); - size--; - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(long key, int value) { - int index = indexOfKey(key); - - if (index >= 0) { - values[index] = value; - } else { - growIfNeeded(); - keys[size] = key; - values[size] = value; - size++; - } - } - - /** - * Returns the number of key-value mappings that this SparseIntArray - * currently stores. - */ - public int size() { - return size; - } - - /** - * Given an index in the range 0...size()-1, returns - * the key from the indexth key-value mapping that this - * SparseLongArray stores. - * - *

The keys corresponding to indices in ascending order are guaranteed to - * be in ascending order, e.g., keyAt(0) will return the - * smallest key and keyAt(size()-1) will return the largest - * key.

- */ - private long keyAt(int index) { - if (index >= size) { - throw new IndexOutOfBoundsException("n >= size()"); - } else if(index < 0) { - throw new IndexOutOfBoundsException("n < 0"); - } - return keys[index]; - } - - /** - * Given an index in the range 0...size()-1, returns - * the value from the indexth key-value mapping that this - * SparseLongArray stores. - * - *

The values corresponding to indices in ascending order are guaranteed - * to be associated with keys in ascending order, e.g., - * valueAt(0) will return the value associated with the - * smallest key and valueAt(size()-1) will return the value - * associated with the largest key.

- */ - private int valueAt(int index) { - if (index >= size) { - throw new IndexOutOfBoundsException("n >= size()"); - } else if(index < 0) { - throw new IndexOutOfBoundsException("n < 0"); - } - return values[index]; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(long key) { - for(int i=0; i < size; i++) { - if(keys[i] == key) { - return i; - } - } - return -1; - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - * Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - */ - public int indexOfValue(long value) { - for (int i = 0; i < size; i++) { - if (values[i] == value) { - return i; - } - } - return -1; - } - - /** - * Removes all key-value mappings from this SparseIntArray. - */ - public void clear() { - keys = new long[10]; - values = new int[10]; - size = 0; - } - - /** - * Returns a copy of the values contained in this map. - * - * @return a copy of the values contained in this map - */ - public int[] values() { - return Arrays.copyOf(values, size); - } - - @Override - public boolean equals(Object other) { - if (other == this) { - return true; - } - if (! (other instanceof LongIntMap)) { - return false; - } - LongIntMap otherMap = (LongIntMap) other; - if (size != otherMap.size) { - return false; - } - for (int i = 0; i < size; i++) { - if (keys[i] != otherMap.keys[i] || - values[i] != otherMap.values[i]) { - return false; - } - } - return true; - } - - @Override - public int hashCode() { - int hashCode = 1; - for (int i = 0; i < size; i++) { - long value = values[i]; - hashCode = 31 * hashCode + (int)(value ^ (value >>> 32)); - } - return hashCode; - } - - @Override - public String toString() { - if (size() <= 0) { - return "LongLongMap{}"; - } - - StringBuilder buffer = new StringBuilder(size * 28); - buffer.append("LongLongMap{"); - for (int i=0; i < size; i++) { - if (i > 0) { - buffer.append(", "); - } - long key = keyAt(i); - buffer.append(key); - buffer.append('='); - long value = valueAt(i); - buffer.append(value); - } - buffer.append('}'); - return buffer.toString(); - } -} diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java index f66c385b7..173354197 100644 --- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java +++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java @@ -1175,7 +1175,7 @@ public class PodDBAdapter { return result; } - public final LongIntMap getFeedCounters(FeedCounter setting, long... feedIds) { + public final Map getFeedCounters(FeedCounter setting, long... feedIds) { String whereRead; switch (setting) { case SHOW_NEW_UNPLAYED_SUM: @@ -1194,12 +1194,12 @@ public class PodDBAdapter { case SHOW_NONE: // deliberate fall-through default: // NONE - return new LongIntMap(0); + return new HashMap<>(); } return conditionalFeedCounterRead(whereRead, feedIds); } - private LongIntMap conditionalFeedCounterRead(String whereRead, long... feedIds) { + private Map conditionalFeedCounterRead(String whereRead, long... feedIds) { String limitFeeds = ""; if (feedIds.length > 0) { // work around TextUtils.join wanting only boxed items @@ -1222,7 +1222,7 @@ public class PodDBAdapter { + whereRead + " GROUP BY " + KEY_FEED; Cursor c = db.rawQuery(query, null); - LongIntMap result = new LongIntMap(c.getCount()); + Map result = new HashMap<>(); if (c.moveToFirst()) { do { long feedId = c.getLong(0); @@ -1234,7 +1234,7 @@ public class PodDBAdapter { return result; } - public final LongIntMap getPlayedEpisodesCounters(long... feedIds) { + public final Map getPlayedEpisodesCounters(long... feedIds) { String whereRead = KEY_READ + "=" + FeedItem.PLAYED; return conditionalFeedCounterRead(whereRead, feedIds); }