Split up DBTasks which has unclear responsibilities (#7032)
This commit is contained in:
parent
130da46f5d
commit
1dbda2fb8a
|
@ -33,7 +33,7 @@ import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter;
|
|||
import de.danoeh.antennapod.ui.common.ThemeSwitcher;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadRequestCreator;
|
||||
import de.danoeh.antennapod.core.feed.FeedUrlNotFoundException;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackServiceInterface;
|
||||
import de.danoeh.antennapod.core.util.DownloadErrorLabel;
|
||||
import de.danoeh.antennapod.databinding.EditTextDialogBinding;
|
||||
|
@ -452,7 +452,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
|||
if (feedInFeedlist()) {
|
||||
openFeed();
|
||||
} else {
|
||||
DBTasks.updateFeed(this, feed, false);
|
||||
FeedDatabaseWriter.updateFeed(this, feed, false);
|
||||
didPressSubscribe = true;
|
||||
handleUpdatedFeedStatus();
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import androidx.core.app.ActivityCompat;
|
|||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.ui.common.ThemeSwitcher;
|
||||
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
|
||||
import de.danoeh.antennapod.databinding.OpmlSelectionBinding;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
|
@ -102,7 +102,7 @@ public class OpmlImportActivity extends AppCompatActivity {
|
|||
Feed feed = new Feed(element.getXmlUrl(), null,
|
||||
element.getText() != null ? element.getText() : "Unknown podcast");
|
||||
feed.setItems(Collections.emptyList());
|
||||
DBTasks.updateFeed(this, feed, false);
|
||||
FeedDatabaseWriter.updateFeed(this, feed, false);
|
||||
}
|
||||
FeedUpdateManager.runOnce(this);
|
||||
})
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
package de.danoeh.antennapod.adapter.actionbutton;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.event.MessageEvent;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.model.playback.MediaType;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
public class PlayActionButton extends ItemActionButton {
|
||||
private static final String TAG = "PlayActionButton";
|
||||
|
||||
public PlayActionButton(FeedItem item) {
|
||||
super(item);
|
||||
|
@ -36,7 +41,12 @@ public class PlayActionButton extends ItemActionButton {
|
|||
return;
|
||||
}
|
||||
if (!media.fileExists()) {
|
||||
DBTasks.notifyMissingFeedMediaFile(context, media);
|
||||
Log.i(TAG, "Missing episode. Will update the database now.");
|
||||
media.setDownloaded(false);
|
||||
media.setLocalFileUrl(null);
|
||||
DBWriter.setFeedMedia(media);
|
||||
EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
|
||||
EventBus.getDefault().post(new MessageEvent(context.getString(R.string.error_file_not_found)));
|
||||
return;
|
||||
}
|
||||
new PlaybackServiceStarter(context, media)
|
||||
|
|
|
@ -29,7 +29,7 @@ import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
|
|||
import de.danoeh.antennapod.activity.OpmlImportActivity;
|
||||
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.model.feed.SortOrder;
|
||||
import de.danoeh.antennapod.databinding.AddfeedBinding;
|
||||
import de.danoeh.antennapod.databinding.EditTextDialogBinding;
|
||||
|
@ -205,7 +205,7 @@ public class AddFeedFragment extends Fragment {
|
|||
Feed dirFeed = new Feed(Feed.PREFIX_LOCAL_FOLDER + uri.toString(), null, title);
|
||||
dirFeed.setItems(Collections.emptyList());
|
||||
dirFeed.setSortOrder(SortOrder.EPISODE_TITLE_A_Z);
|
||||
Feed fromDatabase = DBTasks.updateFeed(getContext(), dirFeed, false);
|
||||
Feed fromDatabase = FeedDatabaseWriter.updateFeed(getContext(), dirFeed, false);
|
||||
FeedUpdateManager.runOnce(requireContext(), fromDatabase);
|
||||
return fromDatabase;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.storage.database.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText;
|
||||
|
@ -340,7 +340,7 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu
|
|||
throw new IllegalArgumentException("Unable to retrieve document tree");
|
||||
}
|
||||
feed.setDownloadUrl(Feed.PREFIX_LOCAL_FOLDER + uri.toString());
|
||||
DBTasks.updateFeed(getContext(), feed, true);
|
||||
FeedDatabaseWriter.updateFeed(getContext(), feed, true);
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
|
|
@ -42,10 +42,10 @@ import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
|
|||
import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.storage.FeedSearcher;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.net.discovery.CombinedSearcher;
|
||||
import de.danoeh.antennapod.storage.database.DBReader;
|
||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||
import de.danoeh.antennapod.view.EpisodeItemListRecyclerView;
|
||||
import de.danoeh.antennapod.view.LiftOnScrollListener;
|
||||
|
@ -407,8 +407,8 @@ public class SearchFragment extends Fragment implements EpisodeItemListAdapter.O
|
|||
return new Pair<>(Collections.emptyList(), Collections.emptyList());
|
||||
}
|
||||
long feed = getArguments().getLong(ARG_FEED);
|
||||
List<FeedItem> items = FeedSearcher.searchFeedItems(query, feed);
|
||||
List<Feed> feeds = FeedSearcher.searchFeeds(query);
|
||||
List<FeedItem> items = DBReader.searchFeedItems(feed, query);
|
||||
List<Feed> feeds = DBReader.searchFeeds(query);
|
||||
return new Pair<>(items, feeds);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@ import android.content.Intent;
|
|||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.core.ClientConfigurator;
|
||||
import de.danoeh.antennapod.core.storage.AutoDownloadManager;
|
||||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
|
||||
// modified from http://developer.android.com/training/monitoring-device-state/battery-monitoring.html
|
||||
// and ConnectivityActionReceiver.java
|
||||
|
@ -32,7 +32,7 @@ public class PowerConnectionReceiver extends BroadcastReceiver {
|
|||
// downloading now. They shouldn't mind.
|
||||
// autodownloadUndownloadedItems will make sure we're on the right wifi networks,
|
||||
// etc... so we don't have to worry about it.
|
||||
DBTasks.autodownloadUndownloadedItems(context);
|
||||
AutoDownloadManager.autodownloadUndownloadedItems(context);
|
||||
} else {
|
||||
// if we're not supposed to be auto-downloading when we're not charging, stop it
|
||||
if (!UserPreferences.isEnableAutodownloadOnBattery()) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Collections;
|
|||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.ClientConfigurator;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
|
||||
|
@ -46,7 +46,7 @@ public class SPAReceiver extends BroadcastReceiver{
|
|||
for (String url : feedUrls) {
|
||||
Feed feed = new Feed(url, null, "Unknown podcast");
|
||||
feed.setItems(Collections.emptyList());
|
||||
DBTasks.updateFeed(context, feed, false);
|
||||
FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||
}
|
||||
Toast.makeText(context, R.string.sp_apps_importing_feeds_msg, Toast.LENGTH_LONG).show();
|
||||
FeedUpdateManager.runOnce(context);
|
||||
|
|
|
@ -8,7 +8,7 @@ import android.content.Context;
|
|||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
|
||||
import de.danoeh.antennapod.storage.importexport.OpmlElement;
|
||||
import de.danoeh.antennapod.storage.importexport.OpmlReader;
|
||||
|
@ -146,7 +146,7 @@ public class OpmlBackupAgent extends BackupAgentHelper {
|
|||
for (OpmlElement opmlElem : opmlElements) {
|
||||
Feed feed = new Feed(opmlElem.getXmlUrl(), null, opmlElem.getText());
|
||||
feed.setItems(Collections.emptyList());
|
||||
DBTasks.updateFeed(mContext, feed, false);
|
||||
FeedDatabaseWriter.updateFeed(mContext, feed, false);
|
||||
}
|
||||
FeedUpdateManager.runOnce(mContext);
|
||||
} catch (XmlPullParserException e) {
|
||||
|
|
|
@ -31,7 +31,7 @@ import de.danoeh.antennapod.core.util.FastDocumentFile;
|
|||
import de.danoeh.antennapod.model.MediaMetadataRetrieverCompat;
|
||||
import de.danoeh.antennapod.model.download.DownloadResult;
|
||||
import de.danoeh.antennapod.storage.database.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.parser.feed.util.DateUtils;
|
||||
import de.danoeh.antennapod.model.download.DownloadError;
|
||||
|
@ -82,7 +82,7 @@ public class LocalFeedUpdater {
|
|||
feed.setItems(new ArrayList<>());
|
||||
}
|
||||
//make sure it is the latest 'version' of this feed from the db (all items etc)
|
||||
feed = DBTasks.updateFeed(context, feed, false);
|
||||
feed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||
|
||||
// list files in feed folder
|
||||
List<FastDocumentFile> allFiles = FastDocumentFile.list(context, folderUri);
|
||||
|
@ -127,7 +127,7 @@ public class LocalFeedUpdater {
|
|||
feed.setDescription(context.getString(R.string.local_feed_description));
|
||||
feed.setAuthor(context.getString(R.string.local_folder));
|
||||
|
||||
DBTasks.updateFeed(context, feed, true);
|
||||
FeedDatabaseWriter.updateFeed(context, feed, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,8 +24,9 @@ import de.danoeh.antennapod.core.service.download.DownloadRequestCreator;
|
|||
import de.danoeh.antennapod.core.service.download.Downloader;
|
||||
import de.danoeh.antennapod.core.service.download.NewEpisodesNotification;
|
||||
import de.danoeh.antennapod.core.service.download.handler.FeedParserTask;
|
||||
import de.danoeh.antennapod.core.storage.AutoDownloadManager;
|
||||
import de.danoeh.antennapod.storage.database.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.net.common.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
|
||||
|
@ -99,7 +100,7 @@ public class FeedUpdateWorker extends Worker {
|
|||
refreshFeeds(toUpdate, force);
|
||||
|
||||
notificationManager.cancel(R.id.notification_updating_feeds);
|
||||
DBTasks.autodownloadUndownloadedItems(getApplicationContext());
|
||||
AutoDownloadManager.autodownloadUndownloadedItems(getApplicationContext());
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
@ -199,7 +200,7 @@ public class FeedUpdateWorker extends Worker {
|
|||
return;
|
||||
}
|
||||
feedHandlerResult.feed.setLastRefreshAttempt(System.currentTimeMillis());
|
||||
Feed savedFeed = DBTasks.updateFeed(getApplicationContext(), feedHandlerResult.feed, false);
|
||||
Feed savedFeed = FeedDatabaseWriter.updateFeed(getApplicationContext(), feedHandlerResult.feed, false);
|
||||
|
||||
if (request.getFeedfileId() == 0) {
|
||||
return; // No download logs for new subscriptions
|
||||
|
|
|
@ -72,7 +72,6 @@ import de.danoeh.antennapod.core.service.QuickSettingsTileService;
|
|||
import de.danoeh.antennapod.core.service.playback.PlaybackServiceTaskManager.SleepTimer;
|
||||
import de.danoeh.antennapod.storage.database.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.FeedSearcher;
|
||||
import de.danoeh.antennapod.core.sync.queue.SynchronizationQueueSink;
|
||||
import de.danoeh.antennapod.core.util.ChapterUtils;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
|
@ -1842,7 +1841,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
|||
return;
|
||||
}
|
||||
|
||||
List<FeedItem> results = FeedSearcher.searchFeedItems(query, 0);
|
||||
List<FeedItem> results = DBReader.searchFeedItems(0, query);
|
||||
if (results.size() > 0 && results.get(0).getMedia() != null) {
|
||||
FeedMedia media = results.get(0).getMedia();
|
||||
startPlaying(media, false);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public abstract class AutoDownloadManager {
|
||||
private static final String TAG = "AutoDownloadManager";
|
||||
|
||||
/**
|
||||
* Executor service used by the autodownloadUndownloadedEpisodes method.
|
||||
*/
|
||||
private static final ExecutorService autodownloadExec;
|
||||
|
||||
private static AutomaticDownloadAlgorithm downloadAlgorithm = new AutomaticDownloadAlgorithm();
|
||||
|
||||
static {
|
||||
autodownloadExec = Executors.newSingleThreadExecutor(r -> {
|
||||
Thread t = new Thread(r);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for non-downloaded episodes in the queue or list of unread items and request a download if
|
||||
* 1. Network is available
|
||||
* 2. The device is charging or the user allows auto download on battery
|
||||
* 3. There is free space in the episode cache
|
||||
* This method is executed on an internal single thread executor.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @return A Future that can be used for waiting for the methods completion.
|
||||
*/
|
||||
public static Future<?> autodownloadUndownloadedItems(final Context context) {
|
||||
Log.d(TAG, "autodownloadUndownloadedItems");
|
||||
return autodownloadExec.submit(downloadAlgorithm.autoDownloadUndownloadedItems(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed downloaded episodes outside of the queue if the episode cache is full. Episodes with a smaller
|
||||
* 'playbackCompletionDate'-value will be deleted first.
|
||||
* <p/>
|
||||
* This method should NOT be executed on the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
*/
|
||||
public static void performAutoCleanup(final Context context) {
|
||||
EpisodeCleanupAlgorithmFactory.build().performCleanup(context);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.storage;
|
|||
|
||||
import android.app.backup.BackupManager;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -27,6 +28,7 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
@ -366,7 +368,7 @@ public class DBWriter {
|
|||
|
||||
adapter.close();
|
||||
if (performAutoDownload) {
|
||||
DBTasks.autodownloadUndownloadedItems(context);
|
||||
AutoDownloadManager.autodownloadUndownloadedItems(context);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -460,7 +462,7 @@ public class DBWriter {
|
|||
}
|
||||
adapter.close();
|
||||
if (performAutoDownload) {
|
||||
DBTasks.autodownloadUndownloadedItems(context);
|
||||
AutoDownloadManager.autodownloadUndownloadedItems(context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -569,7 +571,7 @@ public class DBWriter {
|
|||
}
|
||||
adapter.close();
|
||||
if (performAutoDownload) {
|
||||
DBTasks.autodownloadUndownloadedItems(context);
|
||||
AutoDownloadManager.autodownloadUndownloadedItems(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1016,6 +1018,38 @@ public class DBWriter {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the feed with the given download url. This method should NOT be executed on the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the db
|
||||
* @param downloadUrl URL of the feed.
|
||||
*/
|
||||
public static void removeFeedWithDownloadUrl(Context context, String downloadUrl) {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor cursor = adapter.getFeedCursorDownloadUrls();
|
||||
long feedId = 0;
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
if (cursor.getString(1).equals(downloadUrl)) {
|
||||
feedId = cursor.getLong(0);
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
adapter.close();
|
||||
|
||||
if (feedId != 0) {
|
||||
try {
|
||||
deleteFeed(context, feedId).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "removeFeedWithDownloadUrl: Could not find feed with url: " + downloadUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit to the DB thread only if caller is not already on the DB thread. Otherwise,
|
||||
* just execute synchronously
|
||||
|
|
|
@ -1,26 +1,19 @@
|
|||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.sync.queue.SynchronizationQueueSink;
|
||||
import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
|
||||
import de.danoeh.antennapod.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.event.FeedListUpdateEvent;
|
||||
import de.danoeh.antennapod.event.MessageEvent;
|
||||
import de.danoeh.antennapod.model.download.DownloadError;
|
||||
import de.danoeh.antennapod.model.download.DownloadResult;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||
import de.danoeh.antennapod.net.sync.model.EpisodeAction;
|
||||
import de.danoeh.antennapod.storage.database.DBReader;
|
||||
import de.danoeh.antennapod.storage.database.PodDBAdapter;
|
||||
import de.danoeh.antennapod.storage.database.mapper.FeedCursorMapper;
|
||||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
|
@ -29,116 +22,13 @@ import java.util.Collections;
|
|||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* Provides methods for doing common tasks that use DBReader and DBWriter.
|
||||
* Creates and updates feeds in the database.
|
||||
*/
|
||||
public final class DBTasks {
|
||||
private static final String TAG = "DBTasks";
|
||||
|
||||
/**
|
||||
* Executor service used by the autodownloadUndownloadedEpisodes method.
|
||||
*/
|
||||
private static final ExecutorService autodownloadExec;
|
||||
|
||||
private static AutomaticDownloadAlgorithm downloadAlgorithm = new AutomaticDownloadAlgorithm();
|
||||
|
||||
static {
|
||||
autodownloadExec = Executors.newSingleThreadExecutor(r -> {
|
||||
Thread t = new Thread(r);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
private DBTasks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the feed with the given download url. This method should NOT be executed on the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the db
|
||||
* @param downloadUrl URL of the feed.
|
||||
*/
|
||||
public static void removeFeedWithDownloadUrl(Context context, String downloadUrl) {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
Cursor cursor = adapter.getFeedCursorDownloadUrls();
|
||||
long feedID = 0;
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
if (cursor.getString(1).equals(downloadUrl)) {
|
||||
feedID = cursor.getLong(0);
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
adapter.close();
|
||||
|
||||
if (feedID != 0) {
|
||||
try {
|
||||
DBWriter.deleteFeed(context, feedID).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "removeFeedWithDownloadUrl: Could not find feed with url: " + downloadUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the database about a missing FeedMedia file. This method will correct the FeedMedia object's
|
||||
* values in the DB and send a FeedItemEvent.
|
||||
*/
|
||||
public static void notifyMissingFeedMediaFile(final Context context, final FeedMedia media) {
|
||||
Log.i(TAG, "The feedmanager was notified about a missing episode. It will update its database now.");
|
||||
media.setDownloaded(false);
|
||||
media.setLocalFileUrl(null);
|
||||
DBWriter.setFeedMedia(media);
|
||||
EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
|
||||
EventBus.getDefault().post(new MessageEvent(context.getString(R.string.error_file_not_found)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for non-downloaded episodes in the queue or list of unread items and request a download if
|
||||
* 1. Network is available
|
||||
* 2. The device is charging or the user allows auto download on battery
|
||||
* 3. There is free space in the episode cache
|
||||
* This method is executed on an internal single thread executor.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @return A Future that can be used for waiting for the methods completion.
|
||||
*/
|
||||
public static Future<?> autodownloadUndownloadedItems(final Context context) {
|
||||
Log.d(TAG, "autodownloadUndownloadedItems");
|
||||
return autodownloadExec.submit(downloadAlgorithm.autoDownloadUndownloadedItems(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing purpose only.
|
||||
*/
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
|
||||
public static void setDownloadAlgorithm(AutomaticDownloadAlgorithm newDownloadAlgorithm) {
|
||||
downloadAlgorithm = newDownloadAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed downloaded episodes outside of the queue if the episode cache is full. Episodes with a smaller
|
||||
* 'playbackCompletionDate'-value will be deleted first.
|
||||
* <p/>
|
||||
* This method should NOT be executed on the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
*/
|
||||
public static void performAutoCleanup(final Context context) {
|
||||
EpisodeCleanupAlgorithmFactory.build().performCleanup(context);
|
||||
}
|
||||
public abstract class FeedDatabaseWriter {
|
||||
private static final String TAG = "FeedDbWriter";
|
||||
|
||||
private static Feed searchFeedByIdentifyingValueOrID(Feed feed) {
|
||||
if (feed.getId() != 0) {
|
||||
|
@ -191,10 +81,6 @@ public final class DBTasks {
|
|||
* Adds new Feeds to the database or updates the old versions if they already exists. If another Feed with the same
|
||||
* identifying value already exists, this method will add new FeedItems from the new Feed to the existing Feed.
|
||||
* These FeedItems will be marked as unread with the exception of the most recent FeedItem.
|
||||
* <p/>
|
||||
* This method can update multiple feeds at once. Submitting a feed twice in the same method call can result in undefined behavior.
|
||||
* <p/>
|
||||
* This method should NOT be executed on the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @param newFeed The new Feed object.
|
||||
|
@ -373,70 +259,4 @@ public final class DBTasks {
|
|||
+ "\nID: " + item.getItemIdentifier()
|
||||
+ ((item.getMedia() == null) ? "" : "\nURL: " + item.getMedia().getDownloadUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the FeedItems of a specific Feed for a given string.
|
||||
*
|
||||
* @param feedID The id of the feed whose items should be searched.
|
||||
* @param query The search string.
|
||||
* @return A FutureTask object that executes the search request
|
||||
* and returns the search result as a List of FeedItems.
|
||||
*/
|
||||
public static FutureTask<List<FeedItem>> searchFeedItems(final long feedID, final String query) {
|
||||
return new FutureTask<>(new QueryTask<List<FeedItem>>() {
|
||||
@Override
|
||||
public void execute(PodDBAdapter adapter) {
|
||||
Cursor searchResult = adapter.searchItems(feedID, query);
|
||||
List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult);
|
||||
DBReader.loadAdditionalFeedItemListData(items);
|
||||
setResult(items);
|
||||
searchResult.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static FutureTask<List<Feed>> searchFeeds(final String query) {
|
||||
return new FutureTask<>(new QueryTask<List<Feed>>() {
|
||||
@Override
|
||||
public void execute(PodDBAdapter adapter) {
|
||||
Cursor cursor = adapter.searchFeeds(query);
|
||||
List<Feed> items = new ArrayList<>();
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
items.add(FeedCursorMapper.convert(cursor));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
setResult(items);
|
||||
cursor.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A runnable which should be used for database queries. The onCompletion
|
||||
* method is executed on the database executor to handle Cursors correctly.
|
||||
* This class automatically creates a PodDBAdapter object and closes it when
|
||||
* it is no longer in use.
|
||||
*/
|
||||
abstract static class QueryTask<T> implements Callable<T> {
|
||||
private T result;
|
||||
|
||||
public QueryTask() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
execute(adapter);
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
public abstract void execute(PodDBAdapter adapter);
|
||||
|
||||
void setResult(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import de.danoeh.antennapod.model.feed.Feed;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* Performs search on Feeds and FeedItems.
|
||||
*/
|
||||
public class FeedSearcher {
|
||||
private FeedSearcher() {
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static List<FeedItem> searchFeedItems(final String query, final long selectedFeed) {
|
||||
try {
|
||||
FutureTask<List<FeedItem>> itemSearchTask = DBTasks.searchFeedItems(selectedFeed, query);
|
||||
itemSearchTask.run();
|
||||
return itemSearchTask.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static List<Feed> searchFeeds(final String query) {
|
||||
try {
|
||||
FutureTask<List<Feed>> feedSearchTask = DBTasks.searchFeeds(query);
|
||||
feedSearchTask.run();
|
||||
return feedSearchTask.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ import de.danoeh.antennapod.event.SyncServiceEvent;
|
|||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.net.common.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.storage.database.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.FeedDatabaseWriter;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.sync.queue.SynchronizationQueueStorage;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
|
@ -158,7 +158,7 @@ public class SyncService extends Worker {
|
|||
if (!UrlChecker.containsUrl(localSubscriptions, downloadUrl) && !queuedRemovedFeeds.contains(downloadUrl)) {
|
||||
Feed feed = new Feed(downloadUrl, null, "Unknown podcast");
|
||||
feed.setItems(Collections.emptyList());
|
||||
Feed newFeed = DBTasks.updateFeed(getApplicationContext(), feed, false);
|
||||
Feed newFeed = FeedDatabaseWriter.updateFeed(getApplicationContext(), feed, false);
|
||||
FeedUpdateManager.runOnce(getApplicationContext(), newFeed);
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ public class SyncService extends Worker {
|
|||
// remove subscription if not just subscribed (again)
|
||||
for (String downloadUrl : subscriptionChanges.getRemoved()) {
|
||||
if (!queuedAddedFeeds.contains(downloadUrl)) {
|
||||
DBTasks.removeFeedWithDownloadUrl(getApplicationContext(), downloadUrl);
|
||||
DBWriter.removeFeedWithDownloadUrl(getApplicationContext(), downloadUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ package de.danoeh.antennapod.core.util.download;
|
|||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.core.storage.AutoDownloadManager;
|
||||
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.net.common.NetworkUtils;
|
||||
|
||||
public abstract class NetworkConnectionChangeHandler {
|
||||
|
@ -17,7 +17,7 @@ public abstract class NetworkConnectionChangeHandler {
|
|||
public static void networkChangedDetected() {
|
||||
if (NetworkUtils.isAutoDownloadAllowed()) {
|
||||
Log.d(TAG, "auto-dl network available, starting auto-download");
|
||||
DBTasks.autodownloadUndownloadedItems(context);
|
||||
AutoDownloadManager.autodownloadUndownloadedItems(context);
|
||||
} else { // if new network is Wi-Fi, finish ongoing downloads,
|
||||
// otherwise cancel all downloads
|
||||
if (NetworkUtils.isNetworkRestricted()) {
|
||||
|
|
|
@ -115,7 +115,7 @@ public class DbCleanupTests {
|
|||
List<File> files = new ArrayList<>();
|
||||
populateItems(numItems, feed, items, files, FeedItem.PLAYED, false, false);
|
||||
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
if (i < EPISODE_CACHE_SIZE) {
|
||||
assertTrue(files.get(i).exists());
|
||||
|
@ -174,7 +174,7 @@ public class DbCleanupTests {
|
|||
List<File> files = new ArrayList<>();
|
||||
populateItems(numItems, feed, items, files, FeedItem.UNPLAYED, false, false);
|
||||
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (File file : files) {
|
||||
assertTrue(file.exists());
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ public class DbCleanupTests {
|
|||
List<File> files = new ArrayList<>();
|
||||
populateItems(numItems, feed, items, files, FeedItem.PLAYED, true, false);
|
||||
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (File file : files) {
|
||||
assertTrue(file.exists());
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ public class DbCleanupTests {
|
|||
List<File> files = new ArrayList<>();
|
||||
populateItems(numItems, feed, items, files, FeedItem.PLAYED, false, true);
|
||||
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (File file : files) {
|
||||
assertTrue(file.exists());
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ public class DbNullCleanupAlgorithmTest {
|
|||
//noinspection ConstantConditions
|
||||
assertTrue(item.getMedia().getId() != 0);
|
||||
}
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
assertTrue(files.get(i).exists());
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class DbQueueCleanupAlgorithmTest extends DbCleanupTests {
|
|||
List<File> files = new ArrayList<>();
|
||||
populateItems(numItems, feed, items, files, FeedItem.UNPLAYED, false, false);
|
||||
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
if (i < EPISODE_CACHE_SIZE) {
|
||||
assertTrue(files.get(i).exists());
|
||||
|
|
|
@ -37,7 +37,7 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Test class for {@link DBTasks}.
|
||||
* Test class for {@link FeedDatabaseWriter}.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DbTasksTest {
|
||||
|
@ -77,7 +77,7 @@ public class DbTasksTest {
|
|||
feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i,
|
||||
new Date(), FeedItem.UNPLAYED, feed));
|
||||
}
|
||||
Feed newFeed = DBTasks.updateFeed(context, feed, false);
|
||||
Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||
|
||||
assertEquals(feed.getId(), newFeed.getId());
|
||||
assertTrue(feed.getId() != 0);
|
||||
|
@ -97,8 +97,8 @@ public class DbTasksTest {
|
|||
feed1.setItems(new ArrayList<>());
|
||||
feed2.setItems(new ArrayList<>());
|
||||
|
||||
Feed savedFeed1 = DBTasks.updateFeed(context, feed1, false);
|
||||
Feed savedFeed2 = DBTasks.updateFeed(context, feed2, false);
|
||||
Feed savedFeed1 = FeedDatabaseWriter.updateFeed(context, feed1, false);
|
||||
Feed savedFeed2 = FeedDatabaseWriter.updateFeed(context, feed2, false);
|
||||
|
||||
assertTrue(savedFeed1.getId() != savedFeed2.getId());
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ public class DbTasksTest {
|
|||
new Date(i), FeedItem.UNPLAYED, feed));
|
||||
}
|
||||
|
||||
final Feed newFeed = DBTasks.updateFeed(context, feed, false);
|
||||
final Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||
assertNotSame(newFeed, feed);
|
||||
|
||||
updatedFeedTest(newFeed, feedID, itemIDs, numItemsOld, numItemsNew);
|
||||
|
@ -167,7 +167,7 @@ public class DbTasksTest {
|
|||
list.add(item);
|
||||
feed.setItems(list);
|
||||
|
||||
final Feed newFeed = DBTasks.updateFeed(context, feed, false);
|
||||
final Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||
assertNotSame(newFeed, feed);
|
||||
|
||||
final Feed feedFromDB = DBReader.getFeed(newFeed.getId());
|
||||
|
@ -190,7 +190,7 @@ public class DbTasksTest {
|
|||
|
||||
// delete some items
|
||||
feed.getItems().subList(0, 2).clear();
|
||||
Feed newFeed = DBTasks.updateFeed(context, feed, true);
|
||||
Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, true);
|
||||
assertEquals(8, newFeed.getItems().size()); // 10 - 2 = 8 items
|
||||
|
||||
Feed feedFromDB = DBReader.getFeed(newFeed.getId());
|
||||
|
@ -217,7 +217,7 @@ public class DbTasksTest {
|
|||
FeedItem item = feed.getItemAtIndex(0);
|
||||
item.setItemIdentifier("id 0-duplicate");
|
||||
item.setTitle("item 0 duplicate");
|
||||
Feed newFeed = DBTasks.updateFeed(context, feed, false);
|
||||
Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||
assertEquals(10, newFeed.getItems().size()); // id 1-duplicate replaces because the stream url is the same
|
||||
|
||||
Feed feedFromDB = DBReader.getFeed(newFeed.getId());
|
||||
|
|
|
@ -35,7 +35,7 @@ public class ExceptFavoriteCleanupAlgorithmTest extends DbCleanupTests {
|
|||
List<File> files = new ArrayList<>();
|
||||
populateItems(numberOfItems, feed, items, files, FeedItem.UNPLAYED, false, false);
|
||||
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
if (i < EPISODE_CACHE_SIZE) {
|
||||
assertTrue("Only enough items should be deleted", files.get(i).exists());
|
||||
|
@ -53,7 +53,7 @@ public class ExceptFavoriteCleanupAlgorithmTest extends DbCleanupTests {
|
|||
List<File> files = new ArrayList<>();
|
||||
populateItems(numberOfItems, feed, items, files, FeedItem.UNPLAYED, true, false);
|
||||
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
if (i < EPISODE_CACHE_SIZE) {
|
||||
assertTrue("Only enough items should be deleted", files.get(i).exists());
|
||||
|
@ -71,7 +71,7 @@ public class ExceptFavoriteCleanupAlgorithmTest extends DbCleanupTests {
|
|||
List<File> files = new ArrayList<>();
|
||||
populateItems(numberOfItems, feed, items, files, FeedItem.UNPLAYED, false, true);
|
||||
|
||||
DBTasks.performAutoCleanup(context);
|
||||
AutoDownloadManager.performAutoCleanup(context);
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
assertTrue("Favorite episodes should should not be deleted", files.get(i).exists());
|
||||
}
|
||||
|
|
|
@ -857,4 +857,28 @@ public final class DBReader {
|
|||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<FeedItem> searchFeedItems(final long feedId, final String query) {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance().open();
|
||||
Cursor searchResult = adapter.searchItems(feedId, query);
|
||||
List<FeedItem> items = extractItemlistFromCursor(searchResult);
|
||||
loadAdditionalFeedItemListData(items);
|
||||
searchResult.close();
|
||||
adapter.close();
|
||||
return items;
|
||||
}
|
||||
|
||||
public static List<Feed> searchFeeds(final String query) {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
Cursor cursor = adapter.searchFeeds(query);
|
||||
List<Feed> items = new ArrayList<>();
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
items.add(FeedCursorMapper.convert(cursor));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
cursor.close();
|
||||
adapter.close();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue