From 75dfc89a445c84e22639d101c229b0cfef6346f0 Mon Sep 17 00:00:00 2001 From: Martin Fietz Date: Wed, 9 Sep 2015 14:05:58 +0200 Subject: Refactor database access --- .../core/asynctask/FlattrClickWorker.java | 2 +- .../core/asynctask/FlattrStatusFetcher.java | 2 +- .../antennapod/core/backup/OpmlBackupAgent.java | 2 +- .../de/danoeh/antennapod/core/feed/Chapter.java | 31 + .../java/de/danoeh/antennapod/core/feed/Feed.java | 63 +- .../de/danoeh/antennapod/core/feed/FeedImage.java | 19 + .../de/danoeh/antennapod/core/feed/FeedItem.java | 36 +- .../antennapod/core/feed/FeedItemFilter.java | 2 +- .../de/danoeh/antennapod/core/feed/FeedMedia.java | 68 +- .../antennapod/core/feed/FeedPreferences.java | 25 +- .../antennapod/core/glide/ApOkHttpUrlLoader.java | 2 +- .../core/service/GpodnetSyncService.java | 14 +- .../core/service/download/DownloadService.java | 21 +- .../core/service/download/DownloadStatus.java | 31 +- .../core/service/playback/PlaybackService.java | 4 +- .../playback/PlaybackServiceMediaPlayer.java | 4 +- .../playback/PlaybackServiceTaskManager.java | 2 +- .../core/storage/APCleanupAlgorithm.java | 44 +- .../core/storage/APDownloadAlgorithm.java | 8 +- .../danoeh/antennapod/core/storage/DBReader.java | 593 ++++------- .../de/danoeh/antennapod/core/storage/DBTasks.java | 48 +- .../danoeh/antennapod/core/storage/DBWriter.java | 1082 ++++++++------------ .../core/storage/EpisodeCleanupAlgorithm.java | 4 +- .../core/storage/FeedItemStatistics.java | 11 + .../antennapod/core/storage/PodDBAdapter.java | 212 +--- .../danoeh/antennapod/core/util/NetworkUtils.java | 2 +- .../danoeh/antennapod/core/util/QueueSorter.java | 2 +- .../antennapod/core/util/flattr/FlattrUtils.java | 2 +- .../core/util/gui/UndoBarController.java | 4 +- .../antennapod/core/util/playback/Playable.java | 2 +- .../core/util/playback/PlaybackController.java | 8 +- 31 files changed, 1025 insertions(+), 1325 deletions(-) (limited to 'core/src/main') diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java index f91d4557e..93b584677 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java @@ -94,7 +94,7 @@ public class FlattrClickWorker extends AsyncTask flattrQueue = DBReader.getFlattrQueue(context); + final List flattrQueue = DBReader.getFlattrQueue(); if (extraFlattrThing != null) { flattrQueue.add(extraFlattrThing); } else if (flattrQueue.size() == 1) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java index c4aa76ac7..888591e89 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrStatusFetcher.java @@ -32,7 +32,7 @@ public class FlattrStatusFetcher extends Thread { try { List flattredThings = FlattrUtils.retrieveFlattredThings(); - DBWriter.setFlattredStatus(context, flattredThings).get(); + DBWriter.setFlattredStatus(flattredThings).get(); } catch (FlattrException e) { e.printStackTrace(); Log.d(TAG, "flattrQueue exception retrieving list with flattred items " + e.getMessage()); diff --git a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java index 1535e2e9a..5ea0ba904 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java @@ -89,7 +89,7 @@ public class OpmlBackupAgent extends BackupAgentHelper { try { // Write OPML - new OpmlWriter().writeDocument(DBReader.getFeedList(mContext), writer); + new OpmlWriter().writeDocument(DBReader.getFeedList(), writer); // Compare checksum of new and old file to see if we need to perform a backup at all if (digester != null) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java index ce3352ed6..bb594ff87 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java @@ -1,5 +1,9 @@ package de.danoeh.antennapod.core.feed; +import android.database.Cursor; + +import de.danoeh.antennapod.core.storage.PodDBAdapter; + public abstract class Chapter extends FeedComponent { /** Defines starting point in milliseconds. */ @@ -22,6 +26,33 @@ public abstract class Chapter extends FeedComponent { this.link = link; } + public static Chapter fromCursor(Cursor cursor, FeedItem item) { + int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); + int indexStart = cursor.getColumnIndex(PodDBAdapter.KEY_START); + int indexLink = cursor.getColumnIndex(PodDBAdapter.KEY_LINK); + int indexChapterType = cursor.getColumnIndex(PodDBAdapter.KEY_CHAPTER_TYPE); + + String title = cursor.getString(indexTitle); + long start = cursor.getLong(indexStart); + String link = cursor.getString(indexLink); + int chapterType = cursor.getInt(indexChapterType); + + Chapter chapter = null; + switch (chapterType) { + case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: + chapter = new SimpleChapter(start, title, item, link); + break; + case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: + chapter = new ID3Chapter(start, title, item, link); + break; + case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: + chapter = new VorbisCommentChapter(start, title, item, link); + break; + } + return chapter; + } + + public abstract int getChapterType(); public long getStart() { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java index 2a483ca9b..6b93723a0 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java @@ -1,6 +1,7 @@ package de.danoeh.antennapod.core.feed; import android.content.Context; +import android.database.Cursor; import android.net.Uri; import android.support.annotation.Nullable; @@ -12,6 +13,7 @@ import java.util.List; import de.danoeh.antennapod.core.asynctask.ImageResource; import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.flattr.FlattrStatus; import de.danoeh.antennapod.core.util.flattr.FlattrThing; @@ -170,11 +172,60 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource { preferences = new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, username, password); } - - /** - * Returns true if at least one item in the itemlist is unread. - * - */ + public static Feed fromCursor(Cursor cursor) { + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + int indexLastUpdate = cursor.getColumnIndex(PodDBAdapter.KEY_LASTUPDATE); + int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); + int indexLink = cursor.getColumnIndex(PodDBAdapter.KEY_LINK); + int indexDescription = cursor.getColumnIndex(PodDBAdapter.KEY_DESCRIPTION); + int indexPaymentLink = cursor.getColumnIndex(PodDBAdapter.KEY_PAYMENT_LINK); + int indexAuthor = cursor.getColumnIndex(PodDBAdapter.KEY_AUTHOR); + int indexLanguage = cursor.getColumnIndex(PodDBAdapter.KEY_LANGUAGE); + int indexType = cursor.getColumnIndex(PodDBAdapter.KEY_TYPE); + int indexFeedIdentifier = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_IDENTIFIER); + int indexFileUrl = cursor.getColumnIndex(PodDBAdapter.KEY_FILE_URL); + int indexDownloadUrl = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL); + int indexDownloaded = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOADED); + int indexFlattrStatus = cursor.getColumnIndex(PodDBAdapter.KEY_FLATTR_STATUS); + int indexIsPaged = cursor.getColumnIndex(PodDBAdapter.KEY_IS_PAGED); + int indexNextPageLink = cursor.getColumnIndex(PodDBAdapter.KEY_NEXT_PAGE_LINK); + int indexHide = cursor.getColumnIndex(PodDBAdapter.KEY_HIDE); + int indexLastUpdateFailed = cursor.getColumnIndex(PodDBAdapter.KEY_LAST_UPDATE_FAILED); + + Date lastUpdate = new Date(cursor.getLong(indexLastUpdate)); + + Feed feed = new Feed( + cursor.getLong(indexId), + lastUpdate, + cursor.getString(indexTitle), + cursor.getString(indexLink), + cursor.getString(indexDescription), + cursor.getString(indexPaymentLink), + cursor.getString(indexAuthor), + cursor.getString(indexLanguage), + cursor.getString(indexType), + cursor.getString(indexFeedIdentifier), + null, + cursor.getString(indexFileUrl), + cursor.getString(indexDownloadUrl), + cursor.getInt(indexDownloaded) > 0, + new FlattrStatus(cursor.getLong(indexFlattrStatus)), + cursor.getInt(indexIsPaged) > 0, + cursor.getString(indexNextPageLink), + cursor.getString(indexHide), + cursor.getInt(indexLastUpdateFailed) > 0 + ); + + FeedPreferences preferences = FeedPreferences.fromCursor(cursor); + feed.setPreferences(preferences); + return feed; + } + + + /** + * Returns true if at least one item in the itemlist is unread. + * + */ public boolean hasNewItems() { for (FeedItem item : items) { if (item.isNew()) { @@ -444,7 +495,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource { } public void savePreferences(Context context) { - DBWriter.setFeedPreferences(context, preferences); + DBWriter.setFeedPreferences(preferences); } @Override diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedImage.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedImage.java index f77a78721..bd7ceb54f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedImage.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedImage.java @@ -1,10 +1,12 @@ package de.danoeh.antennapod.core.feed; +import android.database.Cursor; import android.net.Uri; import java.io.File; import de.danoeh.antennapod.core.asynctask.ImageResource; +import de.danoeh.antennapod.core.storage.PodDBAdapter; public class FeedImage extends FeedFile implements ImageResource { @@ -31,6 +33,23 @@ public class FeedImage extends FeedFile implements ImageResource { super(); } + public static FeedImage fromCursor(Cursor cursor) { + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); + int indexFileUrl = cursor.getColumnIndex(PodDBAdapter.KEY_FILE_URL); + int indexDownloadUrl = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL); + int indexDownloaded = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOADED); + + return new FeedImage( + cursor.getLong(indexId), + cursor.getString(indexTitle), + cursor.getString(indexFileUrl), + cursor.getString(indexDownloadUrl), + cursor.getInt(indexDownloaded) > 0 + ); + } + + @Override public String getHumanReadableIdentifier() { if (owner != null && owner.getHumanReadableIdentifier() != null) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java index 9229172f0..5c3ed303f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.core.feed; +import android.database.Cursor; import android.net.Uri; import org.apache.commons.lang3.builder.ToStringBuilder; @@ -9,9 +10,9 @@ import java.util.Date; import java.util.List; import java.util.concurrent.Callable; -import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.asynctask.ImageResource; import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.ShownotesProvider; import de.danoeh.antennapod.core.util.flattr.FlattrStatus; import de.danoeh.antennapod.core.util.flattr.FlattrThing; @@ -125,6 +126,37 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr this.hasChapters = hasChapters; } + public static FeedItem fromCursor(Cursor cursor) { + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); + int indexLink = cursor.getColumnIndex(PodDBAdapter.KEY_LINK); + int indexPubDate = cursor.getColumnIndex(PodDBAdapter.KEY_PUBDATE); + int indexPaymentLink = cursor.getColumnIndex(PodDBAdapter.KEY_PAYMENT_LINK); + int indexFeedId = cursor.getColumnIndex(PodDBAdapter.KEY_FEED); + int indexFlattrStatus = cursor.getColumnIndex(PodDBAdapter.KEY_FLATTR_STATUS); + int indexHasChapters = cursor.getColumnIndex(PodDBAdapter.KEY_HAS_CHAPTERS); + int indexRead = cursor.getColumnIndex(PodDBAdapter.KEY_READ); + int indexItemIdentifier = cursor.getColumnIndex(PodDBAdapter.KEY_ITEM_IDENTIFIER); + int indexAutoDownload = cursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DOWNLOAD); + + long id = cursor.getInt(indexId); + assert(id > 0); + String title = cursor.getString(indexTitle); + String link = cursor.getString(indexLink); + Date pubDate = new Date(cursor.getLong(indexPubDate)); + String paymentLink = cursor.getString(indexPaymentLink); + long feedId = cursor.getLong(indexFeedId); + boolean hasChapters = cursor.getInt(indexHasChapters) > 0; + FlattrStatus flattrStatus = new FlattrStatus(cursor.getLong(indexFlattrStatus)); + int state = cursor.getInt(indexRead); + String itemIdentifier = cursor.getString(indexItemIdentifier); + boolean autoDownload = cursor.getInt(indexAutoDownload) > 0; + + FeedItem item = new FeedItem(id, title, link, pubDate, paymentLink, feedId, flattrStatus, + hasChapters, null, state, itemIdentifier, autoDownload); + return item; + } + public void updateFromOther(FeedItem other) { super.updateFromOther(other); if (other.title != null) { @@ -321,7 +353,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr public String call() throws Exception { if (contentEncoded == null || description == null) { - DBReader.loadExtraInformationOfFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), FeedItem.this); + DBReader.loadExtraInformationOfFeedItem(FeedItem.this); } return (contentEncoded != null) ? contentEncoded : description; diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java index 2fd5666c8..879b28096 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java @@ -64,7 +64,7 @@ public class FeedItemFilter { if(hideUnplayed && false == item.isPlayed()) continue; if(hidePaused && item.getState() == FeedItem.State.IN_PROGRESS) continue; if(hidePlayed && item.isPlayed()) continue; - boolean isQueued = DBReader.getQueueIDList(context).contains(item.getId()); + boolean isQueued = DBReader.getQueueIDList().contains(item.getId()); if(hideQueued && isQueued) continue; if(hideNotQueued && false == isQueued) continue; boolean isDownloaded = item.getMedia() != null && item.getMedia().isDownloaded(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java index ddb71fa7e..7397dd935 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.feed; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.database.Cursor; import android.media.MediaMetadataRetriever; import android.net.Uri; import android.os.Parcel; @@ -11,11 +12,11 @@ import java.util.Date; import java.util.List; import java.util.concurrent.Callable; -import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.ChapterUtils; import de.danoeh.antennapod.core.util.playback.Playable; @@ -83,6 +84,55 @@ public class FeedMedia extends FeedFile implements Playable { this.hasEmbeddedPicture = hasEmbeddedPicture; } + public static FeedMedia fromCursor(Cursor cursor) { + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + int indexPlaybackCompletionDate = cursor.getColumnIndex(PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE); + int indexDuration = cursor.getColumnIndex(PodDBAdapter.KEY_DURATION); + int indexPosition = cursor.getColumnIndex(PodDBAdapter.KEY_POSITION); + int indexSize = cursor.getColumnIndex(PodDBAdapter.KEY_SIZE); + int indexMimeType = cursor.getColumnIndex(PodDBAdapter.KEY_MIME_TYPE); + int indexFileUrl = cursor.getColumnIndex(PodDBAdapter.KEY_FILE_URL); + int indexDownloadUrl = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL); + int indexDownloaded = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOADED); + int indexPlayedDuration = cursor.getColumnIndex(PodDBAdapter.KEY_PLAYED_DURATION); + + long mediaId = cursor.getLong(indexId); + Date playbackCompletionDate = null; + long playbackCompletionTime = cursor.getLong(indexPlaybackCompletionDate); + if (playbackCompletionTime > 0) { + playbackCompletionDate = new Date(playbackCompletionTime); + } + + Boolean hasEmbeddedPicture; + switch(cursor.getInt(cursor.getColumnIndex(PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE))) { + case 1: + hasEmbeddedPicture = Boolean.TRUE; + break; + case 0: + hasEmbeddedPicture = Boolean.FALSE; + break; + default: + hasEmbeddedPicture = null; + break; + } + + return new FeedMedia( + mediaId, + null, + cursor.getInt(indexDuration), + cursor.getInt(indexPosition), + cursor.getLong(indexSize), + cursor.getString(indexMimeType), + cursor.getString(indexFileUrl), + cursor.getString(indexDownloadUrl), + cursor.getInt(indexDownloaded) > 0, + playbackCompletionDate, + cursor.getInt(indexPlayedDuration), + hasEmbeddedPicture + ); + } + + @Override public String getHumanReadableIdentifier() { if (item != null && item.getTitle() != null) { @@ -297,22 +347,22 @@ public class FeedMedia extends FeedFile implements Playable { @Override public void loadMetadata() throws PlayableException { if (item == null && itemID != 0) { - item = DBReader.getFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), itemID); + item = DBReader.getFeedItem(itemID); } } @Override public void loadChapterMarks() { if (item == null && itemID != 0) { - item = DBReader.getFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), itemID); + item = DBReader.getFeedItem(itemID); } // check if chapters are stored in db and not loaded yet. if (item != null && item.hasChapters() && item.getChapters() == null) { - DBReader.loadChaptersOfFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), item); + DBReader.loadChaptersOfFeedItem(item); } else if (item != null && item.getChapters() == null && !localFileAvailable()) { ChapterUtils.loadChaptersFromStreamUrl(this); if (getChapters() != null && item != null) { - DBWriter.setFeedItem(ClientConfig.applicationCallbacks.getApplicationInstance(), + DBWriter.setFeedItem( item); } } @@ -389,9 +439,9 @@ public class FeedMedia extends FeedFile implements Playable { @Override public void saveCurrentPosition(SharedPreferences pref, int newPosition) { - DBWriter.setFeedMediaPlaybackInformation(ClientConfig.applicationCallbacks.getApplicationInstance(), this); + DBWriter.setFeedMediaPlaybackInformation(this); if(item.isNew()) { - DBWriter.markItemPlayed(ClientConfig.applicationCallbacks.getApplicationInstance(), FeedItem.UNPLAYED, item.getId()); + DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId()); } setPosition(newPosition); } @@ -421,11 +471,11 @@ public class FeedMedia extends FeedFile implements Playable { public String call() throws Exception { if (item == null) { item = DBReader.getFeedItem( - ClientConfig.applicationCallbacks.getApplicationInstance(), itemID); + itemID); } if (item.getContentEncoded() == null || item.getDescription() == null) { DBReader.loadExtraInformationOfFeedItem( - ClientConfig.applicationCallbacks.getApplicationInstance(), item); + item); } return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java index 88da865cc..eb28a3185 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java @@ -1,9 +1,13 @@ package de.danoeh.antennapod.core.feed; import android.content.Context; -import de.danoeh.antennapod.core.storage.DBWriter; +import android.database.Cursor; + import org.apache.commons.lang3.StringUtils; + import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.PodDBAdapter; /** * Contains preferences for a single feed. @@ -29,6 +33,23 @@ public class FeedPreferences { this.password = password; } + public static FeedPreferences fromCursor(Cursor cursor) { + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + int indexAutoDownload = cursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DOWNLOAD); + int indexAutoDeleteAction = cursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DELETE_ACTION); + int indexUsername = cursor.getColumnIndex(PodDBAdapter.KEY_USERNAME); + int indexPassword = cursor.getColumnIndex(PodDBAdapter.KEY_PASSWORD); + + long feedId = cursor.getLong(indexId); + boolean autoDownload = cursor.getInt(indexAutoDownload) > 0; + int autoDeleteActionIndex = cursor.getInt(indexAutoDeleteAction); + AutoDeleteAction autoDeleteAction = AutoDeleteAction.values()[autoDeleteActionIndex]; + String username = cursor.getString(indexUsername); + String password = cursor.getString(indexPassword); + return new FeedPreferences(feedId, autoDownload, autoDeleteAction, username, password); + } + + /** * Compare another FeedPreferences with this one. The feedID, autoDownload and AutoDeleteAction attribute are excluded from the @@ -98,7 +119,7 @@ public class FeedPreferences { } public void save(Context context) { - DBWriter.setFeedPreferences(context, this); + DBWriter.setFeedPreferences(this); } public String getUsername() { diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java index cf3af7d4c..86baa459c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java @@ -108,7 +108,7 @@ public class ApOkHttpUrlLoader implements ModelLoader { com.squareup.okhttp.Request request = chain.request(); String url = request.urlString(); Context context = ClientConfig.applicationCallbacks.getApplicationInstance(); - String authentication = DBReader.getImageAuthentication(context, url); + String authentication = DBReader.getImageAuthentication(url); if(TextUtils.isEmpty(authentication)) { Log.d(TAG, "no credentials for '" + url + "'"); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java index e925f89a7..d5660f67e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java @@ -126,7 +126,7 @@ public class GpodnetSyncService extends Service { private synchronized void syncSubscriptionChanges() { final long timestamp = GpodnetPreferences.getLastSubscriptionSyncTimestamp(); try { - final List localSubscriptions = DBReader.getFeedListDownloadUrls(this); + final List localSubscriptions = DBReader.getFeedListDownloadUrls(); Collection localAdded = GpodnetPreferences.getAddedFeedsCopy(); Collection localRemoved = GpodnetPreferences.getRemovedFeedsCopy(); GpodnetService service = tryLogin(); @@ -242,9 +242,9 @@ public class GpodnetSyncService extends Service { for (GpodnetEpisodeAction action : remoteActions) { switch (action.getAction()) { case NEW: - FeedItem newItem = DBReader.getFeedItem(this, action.getPodcast(), action.getEpisode()); + FeedItem newItem = DBReader.getFeedItem(action.getPodcast(), action.getEpisode()); if(newItem != null) { - DBWriter.markItemPlayed(this, newItem, FeedItem.UNPLAYED, true); + DBWriter.markItemPlayed(newItem, FeedItem.UNPLAYED, true); } else { Log.i(TAG, "Unknown feed item: " + action); } @@ -273,14 +273,14 @@ public class GpodnetSyncService extends Service { } } for (GpodnetEpisodeAction action : mostRecentPlayAction.values()) { - FeedItem playItem = DBReader.getFeedItem(this, action.getPodcast(), action.getEpisode()); + FeedItem playItem = DBReader.getFeedItem(action.getPodcast(), action.getEpisode()); if (playItem != null) { FeedMedia media = playItem.getMedia(); media.setPosition(action.getPosition() * 1000); - DBWriter.setFeedMedia(this, media); + DBWriter.setFeedMedia(media); if(playItem.getMedia().hasAlmostEnded()) { - DBWriter.markItemPlayed(this, playItem, FeedItem.PLAYED, true); - DBWriter.addItemToPlaybackHistory(this, playItem.getMedia()); + DBWriter.markItemPlayed(playItem, FeedItem.PLAYED, true); + DBWriter.addItemToPlaybackHistory(playItem.getMedia()); } } } 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 04ba77cda..36ea1e222 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,7 +20,6 @@ import android.util.Log; import android.webkit.URLUtil; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.http.HttpStatus; @@ -504,7 +503,7 @@ public class DownloadService extends Service { */ private void saveDownloadStatus(DownloadStatus status) { reportQueue.add(status); - DBWriter.addDownloadStatus(this, status); + DBWriter.addDownloadStatus(status); } private void sendDownloadHandledIntent() { @@ -888,7 +887,7 @@ public class DownloadService extends Service { if (successful) { // we create a 'successful' download log if the feed's last refresh failed - List log = DBReader.getFeedDownloadLog(DownloadService.this, feed); + List log = DBReader.getFeedDownloadLog(feed); if(log.size() > 0 && log.get(0).isSuccessful() == false) { saveDownloadStatus(new DownloadStatus(feed, feed.getHumanReadableIdentifier(), DownloadError.SUCCESS, successful, @@ -1011,17 +1010,17 @@ public class DownloadService extends Service { @Override public void run() { if(request.getFeedfileType() == Feed.FEEDFILETYPE_FEED) { - DBWriter.setFeedLastUpdateFailed(DownloadService.this, request.getFeedfileId(), true); + DBWriter.setFeedLastUpdateFailed(request.getFeedfileId(), true); } else if (request.isDeleteOnFailure()) { Log.d(TAG, "Ignoring failed download, deleteOnFailure=true"); } else { File dest = new File(request.getDestination()); if (dest.exists() && request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { Log.d(TAG, "File has been partially downloaded. Writing file url"); - FeedMedia media = DBReader.getFeedMedia(DownloadService.this, request.getFeedfileId()); + FeedMedia media = DBReader.getFeedMedia(request.getFeedfileId()); media.setFile_url(request.getDestination()); try { - DBWriter.setFeedMedia(DownloadService.this, media).get(); + DBWriter.setFeedMedia(media).get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { @@ -1050,7 +1049,7 @@ public class DownloadService extends Service { @Override public void run() { - FeedImage image = DBReader.getFeedImage(DownloadService.this, request.getFeedfileId()); + FeedImage image = DBReader.getFeedImage(request.getFeedfileId()); if (image == null) { throw new IllegalStateException("Could not find downloaded image in database"); } @@ -1060,7 +1059,7 @@ public class DownloadService extends Service { saveDownloadStatus(status); sendDownloadHandledIntent(); - DBWriter.setFeedImage(DownloadService.this, image); + DBWriter.setFeedImage(image); numberOfDownloads.decrementAndGet(); queryDownloadsAsync(); } @@ -1084,7 +1083,7 @@ public class DownloadService extends Service { @Override public void run() { - FeedMedia media = DBReader.getFeedMedia(DownloadService.this, + FeedMedia media = DBReader.getFeedMedia( request.getFeedfileId()); if (media == null) { throw new IllegalStateException( @@ -1126,9 +1125,9 @@ public class DownloadService extends Service { item.setAutoDownload(false); // update the db - DBWriter.setFeedItem(DownloadService.this, item).get(); + DBWriter.setFeedItem(item).get(); - DBWriter.setFeedMedia(DownloadService.this, media).get(); + DBWriter.setFeedMedia(media).get(); if (!DBTasks.isInQueue(DownloadService.this, item.getId())) { DBWriter.addQueueItem(DownloadService.this, item.getId()).get(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java index d05650d10..21928c94f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java @@ -1,12 +1,15 @@ package de.danoeh.antennapod.core.service.download; +import android.database.Cursor; + import org.apache.commons.lang3.Validate; +import java.util.Date; + import de.danoeh.antennapod.core.feed.FeedFile; +import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.DownloadError; -import java.util.Date; - /** Contains status attributes for one download */ public class DownloadStatus { /** @@ -101,6 +104,30 @@ public class DownloadStatus { this.reasonDetailed = reasonDetailed; } + public static DownloadStatus fromCursor(Cursor cursor) { + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE); + int indexFeedFile = cursor.getColumnIndex(PodDBAdapter.KEY_FEEDFILE); + int indexFileFileType = cursor.getColumnIndex(PodDBAdapter.KEY_FEEDFILETYPE); + int indexSuccessful = cursor.getColumnIndex(PodDBAdapter.KEY_SUCCESSFUL); + int indexReason = cursor.getColumnIndex(PodDBAdapter.KEY_REASON); + int indexCompletionDate = cursor.getColumnIndex(PodDBAdapter.KEY_COMPLETION_DATE); + int indexReasonDetailed = cursor.getColumnIndex(PodDBAdapter.KEY_REASON_DETAILED); + + long id = cursor.getLong(indexId); + String title = cursor.getString(indexTitle); + long feedfileId = cursor.getLong(indexFeedFile); + int feedfileType = cursor.getInt(indexFileFileType); + boolean successful = cursor.getInt(indexSuccessful) > 0; + int reason = cursor.getInt(indexReason); + Date completionDate = new Date(cursor.getLong(indexCompletionDate)); + String reasonDetailed = cursor.getString(indexReasonDetailed); + + return new DownloadStatus(id, title, feedfileId, + feedfileType, successful, DownloadError.fromCode(reason), completionDate, + reasonDetailed); + } + @Override public String toString() { return "DownloadStatus [id=" + id + ", title=" + title + ", reason=" diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index 0ccc04238..9b6d17b98 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -564,7 +564,7 @@ public class PlaybackService extends Service { if (playable instanceof FeedMedia) { FeedMedia media = (FeedMedia) playable; FeedItem item = media.getItem(); - DBWriter.markItemPlayed(PlaybackService.this, item, FeedItem.PLAYED, true); + DBWriter.markItemPlayed(item, FeedItem.PLAYED, true); try { final List queue = taskManager.getQueue(); @@ -577,7 +577,7 @@ public class PlaybackService extends Service { if (isInQueue) { DBWriter.removeQueueItem(PlaybackService.this, item, true); } - DBWriter.addItemToPlaybackHistory(PlaybackService.this, media); + DBWriter.addItemToPlaybackHistory(media); // auto-flattr if enabled if (isAutoFlattrable(media) && UserPreferences.getAutoFlattrPlayedDurationThreshold() == 1.0f) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java index c54afc7d6..2012549fc 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java @@ -201,9 +201,9 @@ public class PlaybackServiceMediaPlayer { if(oldMedia.hasAlmostEnded()) { Log.d(TAG, "smart mark as read"); FeedItem item = oldMedia.getItem(); - DBWriter.markItemPlayed(context, item, FeedItem.PLAYED, false); + DBWriter.markItemPlayed(item, FeedItem.PLAYED, false); DBWriter.removeQueueItem(context, item, false); - DBWriter.addItemToPlaybackHistory(context, oldMedia); + DBWriter.addItemToPlaybackHistory(oldMedia); if (item.getFeed().getPreferences().getCurrentAutoDelete()) { Log.d(TAG, "Delete " + oldMedia.toString()); DBWriter.deleteFeedMediaOfItem(context, oldMedia.getId()); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java index 4872dd7bd..dba66a36d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java @@ -100,7 +100,7 @@ public class PlaybackServiceTaskManager { queueFuture = schedExecutor.submit(new Callable>() { @Override public List call() throws Exception { - return DBReader.getQueue(context); + return DBReader.getQueue(); } }); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java index a07705e69..70b3aa90a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java @@ -5,7 +5,6 @@ import android.util.Log; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.concurrent.ExecutionException; @@ -18,13 +17,14 @@ import de.danoeh.antennapod.core.util.LongList; * Implementation of the EpisodeCleanupAlgorithm interface used by AntennaPod. */ public class APCleanupAlgorithm implements EpisodeCleanupAlgorithm { + private static final String TAG = "APCleanupAlgorithm"; @Override public int performCleanup(Context context, Integer episodeNumber) { - List candidates = new ArrayList(); - List downloadedItems = DBReader.getDownloadedItems(context); - LongList queue = DBReader.getQueueIDList(context); + List candidates = new ArrayList<>(); + List downloadedItems = DBReader.getDownloadedItems(); + LongList queue = DBReader.getQueueIDList(); List delete; for (FeedItem item : downloadedItems) { if (item.hasMedia() && item.getMedia().isDownloaded() @@ -34,20 +34,17 @@ public class APCleanupAlgorithm implements EpisodeCleanupAlgorithm { } - Collections.sort(candidates, new Comparator() { - @Override - public int compare(FeedItem lhs, FeedItem rhs) { - Date l = lhs.getMedia().getPlaybackCompletionDate(); - Date r = rhs.getMedia().getPlaybackCompletionDate(); - - if (l == null) { - l = new Date(); - } - if (r == null) { - r = new Date(); - } - return l.compareTo(r); + Collections.sort(candidates, (lhs, rhs) -> { + Date l = lhs.getMedia().getPlaybackCompletionDate(); + Date r = rhs.getMedia().getPlaybackCompletionDate(); + + if (l == null) { + l = new Date(); + } + if (r == null) { + r = new Date(); } + return l.compareTo(r); }); if (candidates.size() > episodeNumber) { @@ -75,22 +72,21 @@ public class APCleanupAlgorithm implements EpisodeCleanupAlgorithm { } @Override - public Integer getDefaultCleanupParameter(Context context) { - return getPerformAutoCleanupArgs(context, 0); + public Integer getDefaultCleanupParameter() { + return getPerformAutoCleanupArgs(0); } @Override - public Integer getPerformCleanupParameter(Context context, List items) { - return getPerformAutoCleanupArgs(context, items.size()); + public Integer getPerformCleanupParameter(List items) { + return getPerformAutoCleanupArgs(items.size()); } - static int getPerformAutoCleanupArgs(Context context, - final int episodeNumber) { + static int getPerformAutoCleanupArgs(final int episodeNumber) { if (episodeNumber >= 0 && UserPreferences.getEpisodeCacheSize() != UserPreferences .getEpisodeCacheSizeUnlimited()) { int downloadedEpisodes = DBReader - .getNumberOfDownloadedEpisodes(context); + .getNumberOfDownloadedEpisodes(); if (downloadedEpisodes + episodeNumber >= UserPreferences .getEpisodeCacheSize()) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java index be9ae1157..f2c56ee79 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APDownloadAlgorithm.java @@ -51,8 +51,8 @@ public class APDownloadAlgorithm implements AutomaticDownloadAlgorithm { Log.d(TAG, "Performing auto-dl of undownloaded episodes"); List candidates; - final List queue = DBReader.getQueue(context); - final List newItems = DBReader.getNewItemsList(context); + final List queue = DBReader.getQueue(); + final List newItems = DBReader.getNewItemsList(); candidates = new ArrayList(queue.size() + newItems.size()); candidates.addAll(queue); for(FeedItem newItem : newItems) { @@ -71,9 +71,9 @@ public class APDownloadAlgorithm implements AutomaticDownloadAlgorithm { } int autoDownloadableEpisodes = candidates.size(); - int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes(context); + int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes(); int deletedEpisodes = cleanupAlgorithm.performCleanup(context, - APCleanupAlgorithm.getPerformAutoCleanupArgs(context, autoDownloadableEpisodes)); + APCleanupAlgorithm.getPerformAutoCleanupArgs(autoDownloadableEpisodes)); boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences .getEpisodeCacheSizeUnlimited(); int episodeCacheSize = UserPreferences.getEpisodeCacheSize(); 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 3da3824a2..4ef4ac067 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 @@ -1,6 +1,5 @@ package de.danoeh.antennapod.core.storage; -import android.content.Context; import android.database.Cursor; import android.util.Log; @@ -9,10 +8,8 @@ import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.List; -import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedImage; @@ -24,13 +21,11 @@ import de.danoeh.antennapod.core.feed.SimpleChapter; import de.danoeh.antennapod.core.feed.VorbisCommentChapter; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadStatus; -import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.core.util.LongIntMap; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.comparator.DownloadStatusComparator; import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator; import de.danoeh.antennapod.core.util.comparator.PlaybackCompletionDateComparator; -import de.danoeh.antennapod.core.util.flattr.FlattrStatus; import de.danoeh.antennapod.core.util.flattr.FlattrThing; /** @@ -40,15 +35,16 @@ import de.danoeh.antennapod.core.util.flattr.FlattrThing; * This class will use the {@link de.danoeh.antennapod.core.feed.EventDistributor} to notify listeners about changes in the database. */ public final class DBReader { + private static final String TAG = "DBReader"; /** - * Maximum size of the list returned by {@link #getPlaybackHistory(android.content.Context)}. + * Maximum size of the list returned by {@link #getPlaybackHistory()}. */ public static final int PLAYBACK_HISTORY_SIZE = 50; /** - * Maximum size of the list returned by {@link #getDownloadLog(android.content.Context)}. + * Maximum size of the list returned by {@link #getDownloadLog()}. */ public static final int DOWNLOAD_LOG_SIZE = 200; @@ -59,16 +55,14 @@ public final class DBReader { /** * Returns a list of Feeds, sorted alphabetically by their title. * - * @param context A context that is used for opening a database connection. * @return A list of Feeds, sorted alphabetically by their title. A Feed-object * of the returned list does NOT have its list of FeedItems yet. The FeedItem-list - * can be loaded separately with {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.core.feed.Feed)}. + * can be loaded separately with {@link #getFeedItemList(Feed)}. */ - public static List getFeedList(final Context context) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Extracting Feedlist"); + public static List getFeedList() { + Log.d(TAG, "Extracting Feedlist"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); List result = getFeedList(adapter); adapter.close(); @@ -76,11 +70,8 @@ public final class DBReader { } private static List getFeedList(PodDBAdapter adapter) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Extracting Feedlist"); - Cursor feedlistCursor = adapter.getAllFeedsCursor(); - List feeds = new ArrayList(feedlistCursor.getCount()); + List feeds = new ArrayList<>(feedlistCursor.getCount()); if (feedlistCursor.moveToFirst()) { do { @@ -95,12 +86,11 @@ public final class DBReader { /** * Returns a list with the download URLs of all feeds. * - * @param context A context that is used for opening the database connection. * @return A list of Strings with the download URLs of all feeds. */ - public static List getFeedListDownloadUrls(final Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); - List result = new ArrayList(); + public static List getFeedListDownloadUrls() { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + List result = new ArrayList<>(); adapter.open(); Cursor feeds = adapter.getFeedCursorDownloadUrls(); if (feeds.moveToFirst()) { @@ -119,12 +109,10 @@ public final class DBReader { * The feedID-attribute of a FeedItem must be set to the ID of its feed or the method will * not find the correct feed of an item. * - * @param context A context that is used for opening a database connection. * @param items The FeedItems whose Feed-objects should be loaded. */ - public static void loadFeedDataOfFeedItemlist(Context context, - List items) { - List feeds = getFeedList(context); + public static void loadFeedDataOfFeedItemlist(List items) { + List feeds = getFeedList(); for (FeedItem item : items) { for (Feed feed : feeds) { if (feed.getId() == item.getFeedId()) { @@ -140,18 +128,16 @@ public final class DBReader { /** * Loads the list of FeedItems for a certain Feed-object. This method should NOT be used if the FeedItems are not - * used. In order to get information ABOUT the list of FeedItems, consider using {@link #getFeedStatisticsList(android.content.Context)} instead. + * used. In order to get information ABOUT the list of FeedItems, consider using {@link #getFeedStatisticsList()} instead. * - * @param context A context that is used for opening a database connection. * @param feed The Feed whose items should be loaded * @return A list with the FeedItems of the Feed. The Feed-attribute of the FeedItems will already be set correctly. * The method does NOT change the items-attribute of the feed. */ - public static List getFeedItemList(Context context, - final Feed feed) { + public static List getFeedItemList(final Feed feed) { Log.d(TAG, "Extracting Feeditems of feed " + feed.getTitle()); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor itemlistCursor = adapter.getAllItemsOfFeedCursor(feed); @@ -170,8 +156,8 @@ public final class DBReader { return items; } - static List extractItemlistFromCursor(Context context, Cursor itemlistCursor) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static List extractItemlistFromCursor(Cursor itemlistCursor) { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); List result = extractItemlistFromCursor(adapter, itemlistCursor); adapter.close(); @@ -180,31 +166,20 @@ public final class DBReader { private static List extractItemlistFromCursor( PodDBAdapter adapter, Cursor itemlistCursor) { - ArrayList itemIds = new ArrayList(); - List items = new ArrayList( - itemlistCursor.getCount()); + ArrayList itemIds = new ArrayList<>(); + List items = new ArrayList<>(itemlistCursor.getCount()); if (itemlistCursor.moveToFirst()) { do { - long imageIndex = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_IMAGE); + int indexImage = itemlistCursor.getColumnIndex(PodDBAdapter.KEY_IMAGE); + long imageId = itemlistCursor.getLong(indexImage); FeedImage image = null; - if (imageIndex != 0) { - image = getFeedImage(adapter, imageIndex); + if (imageId != 0) { + image = getFeedImage(adapter, imageId); } - FeedItem item = new FeedItem(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID), - itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_TITLE), - itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_LINK), - new Date(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE)), - itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK), - itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_FEED), - new FlattrStatus(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS)), - itemlistCursor.getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0, - image, - itemlistCursor.getInt(PodDBAdapter.IDX_FI_SMALL_READ), - itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER), - itemlistCursor.getInt(itemlistCursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DOWNLOAD)) > 0 - ); + FeedItem item = FeedItem.fromCursor(itemlistCursor); + item.setImage(image); itemIds.add(String.valueOf(item.getId())); @@ -219,16 +194,18 @@ public final class DBReader { private static void extractMediafromItemlist(PodDBAdapter adapter, List items, ArrayList itemIds) { - List itemsCopy = new ArrayList(items); + List itemsCopy = new ArrayList<>(items); Cursor cursor = adapter.getFeedMediaCursorByItemID(itemIds .toArray(new String[itemIds.size()])); if (cursor.moveToFirst()) { do { - long itemId = cursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX); + int index = cursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); + long itemId = cursor.getLong(index); // find matching feed item FeedItem item = getMatchingItemForMedia(itemId, itemsCopy); if (item != null) { - item.setMedia(extractFeedMediaFromCursorRow(cursor)); + FeedMedia media = FeedMedia.fromCursor(cursor); + item.setMedia(media); item.getMedia().setItem(item); } } while (cursor.moveToNext()); @@ -236,105 +213,29 @@ public final class DBReader { cursor.close(); } - private static FeedMedia extractFeedMediaFromCursorRow(final Cursor cursor) { - long mediaId = cursor.getLong(PodDBAdapter.KEY_ID_INDEX); - Date playbackCompletionDate = null; - long playbackCompletionTime = cursor - .getLong(PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE_INDEX); - if (playbackCompletionTime > 0) { - playbackCompletionDate = new Date( - playbackCompletionTime); - } - Boolean hasEmbeddedPicture; - switch(cursor.getInt(cursor.getColumnIndex(PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE))) { - case 1: - hasEmbeddedPicture = Boolean.TRUE; - break; - case 0: - hasEmbeddedPicture = Boolean.FALSE; - break; - default: - hasEmbeddedPicture = null; - break; - } - - return new FeedMedia( - mediaId, - null, - cursor.getInt(PodDBAdapter.KEY_DURATION_INDEX), - cursor.getInt(PodDBAdapter.KEY_POSITION_INDEX), - cursor.getLong(PodDBAdapter.KEY_SIZE_INDEX), - cursor.getString(PodDBAdapter.KEY_MIME_TYPE_INDEX), - cursor.getString(PodDBAdapter.KEY_FILE_URL_INDEX), - cursor.getString(PodDBAdapter.KEY_DOWNLOAD_URL_INDEX), - cursor.getInt(PodDBAdapter.KEY_DOWNLOADED_INDEX) > 0, - playbackCompletionDate, - cursor.getInt(PodDBAdapter.KEY_PLAYED_DURATION_INDEX), - hasEmbeddedPicture); - } - private static Feed extractFeedFromCursorRow(PodDBAdapter adapter, Cursor cursor) { - Date lastUpdate = new Date( - cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_LASTUPDATE)); - final FeedImage image; - long imageIndex = cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_IMAGE); - if (imageIndex != 0) { - image = getFeedImage(adapter, imageIndex); + int indexImage = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE); + long imageId = cursor.getLong(indexImage); + if (imageId != 0) { + image = getFeedImage(adapter, imageId); } else { image = null; } - Feed feed = new Feed(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_ID), - lastUpdate, - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_TITLE), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_LINK), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_DESCRIPTION), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_PAYMENT_LINK), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_AUTHOR), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_LANGUAGE), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_TYPE), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_FEED_IDENTIFIER), - image, - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_FILE_URL), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_DOWNLOAD_URL), - cursor.getInt(PodDBAdapter.IDX_FEED_SEL_STD_DOWNLOADED) > 0, - new FlattrStatus(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_FLATTR_STATUS)), - cursor.getInt(PodDBAdapter.IDX_FEED_SEL_STD_IS_PAGED) > 0, - cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_NEXT_PAGE_LINK), - cursor.getString(cursor.getColumnIndex(PodDBAdapter.KEY_HIDE)), - cursor.getInt(cursor.getColumnIndex(PodDBAdapter.KEY_LAST_UPDATE_FAILED)) > 0 - ); + Feed feed = Feed.fromCursor(cursor); if (image != null) { + feed.setImage(image); image.setOwner(feed); } - FeedPreferences preferences = new FeedPreferences(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_ID), - cursor.getInt(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_AUTO_DOWNLOAD) > 0, - FeedPreferences.AutoDeleteAction.values()[cursor.getInt(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_AUTO_DELETE_ACTION)], - cursor.getString(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_USERNAME), - cursor.getString(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_PASSWORD)); + FeedPreferences preferences = FeedPreferences.fromCursor(cursor); feed.setPreferences(preferences); - return feed; - } - private static DownloadStatus extractDownloadStatusFromCursorRow(final Cursor cursor) { - long id = cursor.getLong(PodDBAdapter.KEY_ID_INDEX); - long feedfileId = cursor.getLong(PodDBAdapter.KEY_FEEDFILE_INDEX); - int feedfileType = cursor.getInt(PodDBAdapter.KEY_FEEDFILETYPE_INDEX); - boolean successful = cursor.getInt(PodDBAdapter.KEY_SUCCESSFUL_INDEX) > 0; - int reason = cursor.getInt(PodDBAdapter.KEY_REASON_INDEX); - String reasonDetailed = cursor.getString(PodDBAdapter.KEY_REASON_DETAILED_INDEX); - String title = cursor.getString(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE_INDEX); - Date completionDate = new Date(cursor.getLong(PodDBAdapter.KEY_COMPLETION_DATE_INDEX)); - - return new DownloadStatus(id, title, feedfileId, - feedfileType, successful, DownloadError.fromCode(reason), completionDate, - reasonDetailed); + return feed; } - private static FeedItem getMatchingItemForMedia(long itemId, List items) { for (FeedItem item : items) { @@ -345,33 +246,27 @@ public final class DBReader { return null; } - static List getQueue(Context context, PodDBAdapter adapter) { + static List getQueue(PodDBAdapter adapter) { Log.d(TAG, "getQueue()"); - Cursor itemlistCursor = adapter.getQueueCursor(); - List items = extractItemlistFromCursor(adapter, - itemlistCursor); + List items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(context, items); - + loadFeedDataOfFeedItemlist(items); return items; } /** * Loads the IDs of the FeedItems in the queue. This method should be preferred over - * {@link #getQueue(android.content.Context)} if the FeedItems of the queue are not needed. + * {@link #getQueue()} if the FeedItems of the queue are not needed. * - * @param context A context that is used for opening a database connection. * @return A list of IDs sorted by the same order as the queue. The caller can wrap the returned * list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties. */ - public static LongList getQueueIDList(Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); - + public static LongList getQueueIDList() { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); LongList result = getQueueIDList(adapter); adapter.close(); - return result; } @@ -389,37 +284,19 @@ public final class DBReader { return queueIds; } - - /** - * Return the size of the queue. - * - * @param context A context that is used for opening a database connection. - * @return Size of the queue. - */ - public static int getQueueSize(Context context) { - Log.d(TAG, "getQueueSize()"); - - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - int size = adapter.getQueueSize(); - adapter.close(); - return size; - } - /** * Loads a list of the FeedItems in the queue. If the FeedItems of the queue are not used directly, consider using - * {@link #getQueueIDList(android.content.Context)} instead. + * {@link #getQueueIDList()} instead. * - * @param context A context that is used for opening a database connection. * @return A list of FeedItems sorted by the same order as the queue. The caller can wrap the returned * list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties. */ - public static List getQueue(Context context) { + public static List getQueue() { Log.d(TAG, "getQueue()"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - List items = getQueue(context, adapter); + List items = getQueue(adapter); adapter.close(); return items; } @@ -427,21 +304,19 @@ public final class DBReader { /** * Loads a list of FeedItems whose episode has been downloaded. * - * @param context A context that is used for opening a database connection. * @return A list of FeedItems whose episdoe has been downloaded. */ - public static List getDownloadedItems(Context context) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Extracting downloaded items"); + public static List getDownloadedItems() { + Log.d(TAG, "Extracting downloaded items"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor itemlistCursor = adapter.getDownloadedItemsCursor(); List items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(context, items); + loadFeedDataOfFeedItemlist(items); Collections.sort(items, new FeedItemPubdateComparator()); adapter.close(); @@ -452,22 +327,18 @@ public final class DBReader { /** * Loads a list of FeedItems whose 'read'-attribute is set to false. * - * @param context A context that is used for opening a database connection. * @return A list of FeedItems whose 'read'-attribute it set to false. */ - public static List getUnreadItemsList(Context context) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Extracting unread items list"); + public static List getUnreadItemsList() { + Log.d(TAG, "Extracting unread items list"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor itemlistCursor = adapter.getUnreadItemsCursor(); - List items = extractItemlistFromCursor(adapter, - itemlistCursor); + List items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(context, items); + loadFeedDataOfFeedItemlist(items); adapter.close(); @@ -477,69 +348,41 @@ public final class DBReader { /** * Loads a list of FeedItems that are considered new. * - * @param context A context that is used for opening a database connection. * @return A list of FeedItems that are considered new. */ - public static List getNewItemsList(Context context) { + public static List getNewItemsList() { Log.d(TAG, "getNewItemsList()"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor itemlistCursor = adapter.getNewItemsCursor(); List items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(context, items); + loadFeedDataOfFeedItemlist(items); adapter.close(); return items; } - /** - * Loads the IDs of the FeedItems whose 'read'-attribute is set to false. - * - * @param context A context that is used for opening a database connection. - * @return A list of IDs of the FeedItems whose 'read'-attribute is set to false. This method should be preferred - * over {@link #getUnreadItemsList(android.content.Context)} if the FeedItems in the UnreadItems list are not used. - */ - public static LongList getNewItemIds(Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - Cursor cursor = adapter.getNewItemIdsCursor(); - LongList itemIds = new LongList(cursor.getCount()); - int i = 0; - if (cursor.moveToFirst()) { - do { - long id = cursor.getLong(PodDBAdapter.KEY_ID_INDEX); - itemIds.add(id); - i++; - } while (cursor.moveToNext()); - } - cursor.close(); - return itemIds; - } - /** * Loads a list of FeedItems sorted by pubDate in descending order. * - * @param context A context that is used for opening a database connection. * @param limit The maximum number of episodes that should be loaded. */ - public static List getRecentlyPublishedEpisodes(Context context, int limit) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Extracting recently published items list"); + public static List getRecentlyPublishedEpisodes(int limit) { + Log.d(TAG, "Extracting recently published items list"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor itemlistCursor = adapter.getRecentlyPublishedItemsCursor(limit); - List items = extractItemlistFromCursor(adapter, - itemlistCursor); + List items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(context, items); + loadFeedDataOfFeedItemlist(items); adapter.close(); @@ -550,26 +393,25 @@ public final class DBReader { * Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode * has been completed at least once. * - * @param context A context that is used for opening a database connection. * @return The playback history. The FeedItems are sorted by their media's playbackCompletionDate in descending order. * The size of the returned list is limited by {@link #PLAYBACK_HISTORY_SIZE}. */ - public static List getPlaybackHistory(final Context context) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Loading playback history"); + public static List getPlaybackHistory() { + Log.d(TAG, "Loading playback history"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor mediaCursor = adapter.getCompletedMediaCursor(PLAYBACK_HISTORY_SIZE); String[] itemIds = new String[mediaCursor.getCount()]; for (int i = 0; i < itemIds.length && mediaCursor.moveToPosition(i); i++) { - itemIds[i] = Long.toString(mediaCursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX)); + int index = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); + itemIds[i] = Long.toString(mediaCursor.getLong(index)); } mediaCursor.close(); Cursor itemCursor = adapter.getFeedItemCursor(itemIds); List items = extractItemlistFromCursor(adapter, itemCursor); - loadFeedDataOfFeedItemlist(context, items); + loadFeedDataOfFeedItemlist(items); itemCursor.close(); adapter.close(); @@ -580,23 +422,21 @@ public final class DBReader { /** * Loads the download log from the database. * - * @param context A context that is used for opening a database connection. * @return A list with DownloadStatus objects that represent the download log. * The size of the returned list is limited by {@link #DOWNLOAD_LOG_SIZE}. */ - public static List getDownloadLog(Context context) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Extracting DownloadLog"); + public static List getDownloadLog() { + Log.d(TAG, "Extracting DownloadLog"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor logCursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE); - List downloadLog = new ArrayList( - logCursor.getCount()); + List downloadLog = new ArrayList<>(logCursor.getCount()); if (logCursor.moveToFirst()) { do { - downloadLog.add(extractDownloadStatusFromCursorRow(logCursor)); + DownloadStatus status = DownloadStatus.fromCursor(logCursor); + downloadLog.add(status); } while (logCursor.moveToNext()); } logCursor.close(); @@ -607,50 +447,22 @@ public final class DBReader { /** * Loads the download log for a particular feed from the database. * - * @param context A context that is used for opening a database connection. * @param feed Feed for which the download log is loaded * @return A list with DownloadStatus objects that represent the feed's download log, * newest events first. */ - public static List getFeedDownloadLog(Context context, Feed feed) { - Log.d(TAG, "getFeedDownloadLog(CONTEXT, " + feed.toString() + ")"); + public static List getFeedDownloadLog(Feed feed) { + Log.d(TAG, "getFeedDownloadLog(" + feed.toString() + ")"); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feed.getId()); - List downloadLog = new ArrayList( - cursor.getCount()); + List downloadLog = new ArrayList<>(cursor.getCount()); if (cursor.moveToFirst()) { do { - downloadLog.add(extractDownloadStatusFromCursorRow(cursor)); - } while (cursor.moveToNext()); - } - cursor.close(); - Collections.sort(downloadLog, new DownloadStatusComparator()); - return downloadLog; - } - - /** - * Loads the download log for a particular feed media from the database. - * - * @param context A context that is used for opening a database connection. - * @param media Feed media for which the download log is loaded - * @return A list with DownloadStatus objects that represent the feed media's download log, - * newest events first. - */ - public static List getFeedMediaDownloadLog(Context context, FeedMedia media) { - Log.d(TAG, "getFeedDownloadLog(CONTEXT, " + media.toString() + ")"); - - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - Cursor cursor = adapter.getDownloadLog(FeedMedia.FEEDFILETYPE_FEEDMEDIA, media.getId()); - List downloadLog = new ArrayList( - cursor.getCount()); - - if (cursor.moveToFirst()) { - do { - downloadLog.add(extractDownloadStatusFromCursorRow(cursor)); + DownloadStatus status = DownloadStatus.fromCursor(cursor); + downloadLog.add(status); } while (cursor.moveToNext()); } cursor.close(); @@ -660,24 +472,20 @@ public final class DBReader { /** * Loads the FeedItemStatistics objects of all Feeds in the database. This method should be preferred over - * {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.core.feed.Feed)} if only metadata about + * {@link #getFeedItemList(Feed)} if only metadata about * the FeedItems is needed. * - * @param context A context that is used for opening a database connection. * @return A list of FeedItemStatistics objects sorted alphabetically by their Feed's title. */ - public static List getFeedStatisticsList(final Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static List getFeedStatisticsList() { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - List result = new ArrayList(); + List result = new ArrayList<>(); Cursor cursor = adapter.getFeedStatisticsCursor(); if (cursor.moveToFirst()) { do { - result.add(new FeedItemStatistics(cursor.getLong(PodDBAdapter.IDX_FEEDSTATISTICS_FEED), - cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_NUM_ITEMS), - cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_NEW_ITEMS), - cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_IN_PROGRESS_EPISODES), - new Date(cursor.getLong(PodDBAdapter.IDX_FEEDSTATISTICS_LATEST_EPISODE)))); + FeedItemStatistics fis = FeedItemStatistics.fromCursor(cursor); + result.add(fis); } while (cursor.moveToNext()); } @@ -689,28 +497,26 @@ public final class DBReader { /** * Loads a specific Feed from the database. * - * @param context A context that is used for opening a database connection. * @param feedId The ID of the Feed * @return The Feed or null if the Feed could not be found. The Feeds FeedItems will also be loaded from the * database and the items-attribute will be set correctly. */ - public static Feed getFeed(final Context context, final long feedId) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static Feed getFeed(final long feedId) { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Feed result = getFeed(context, feedId, adapter); + Feed result = getFeed(feedId, adapter); adapter.close(); return result; } - static Feed getFeed(final Context context, final long feedId, PodDBAdapter adapter) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Loading feed with id " + feedId); + static Feed getFeed(final long feedId, PodDBAdapter adapter) { + Log.d(TAG, "Loading feed with id " + feedId); Feed feed = null; Cursor feedCursor = adapter.getFeedCursor(feedId); if (feedCursor.moveToFirst()) { feed = extractFeedFromCursorRow(adapter, feedCursor); - feed.setItems(getFeedItemList(context, feed)); + feed.setItems(getFeedItemList(feed)); } else { Log.e(TAG, "getFeed could not find feed with id " + feedId); } @@ -718,9 +524,8 @@ public final class DBReader { return feed; } - static FeedItem getFeedItem(final Context context, final long itemId, PodDBAdapter adapter) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Loading feeditem with id " + itemId); + static FeedItem getFeedItem(final long itemId, PodDBAdapter adapter) { + Log.d(TAG, "Loading feeditem with id " + itemId); FeedItem item = null; Cursor itemCursor = adapter.getFeedItemCursor(Long.toString(itemId)); @@ -728,7 +533,7 @@ public final class DBReader { List list = extractItemlistFromCursor(adapter, itemCursor); if (list.size() > 0) { item = list.get(0); - loadFeedDataOfFeedItemlist(context, list); + loadFeedDataOfFeedItemlist(list); if (item.hasChapters()) { loadChaptersOfFeedItem(adapter, item); } @@ -738,7 +543,7 @@ public final class DBReader { return item; } - static List getFeedItems(final Context context, PodDBAdapter adapter, final long... itemIds) { + static List getFeedItems(PodDBAdapter adapter, final long... itemIds) { String[] ids = new String[itemIds.length]; for(int i = 0; i < itemIds.length; i++) { @@ -751,7 +556,7 @@ public final class DBReader { Cursor itemCursor = adapter.getFeedItemCursor(ids); if (itemCursor.moveToFirst()) { result = extractItemlistFromCursor(adapter, itemCursor); - loadFeedDataOfFeedItemlist(context, result); + loadFeedDataOfFeedItemlist(result); for(FeedItem item : result) { if (item.hasChapters()) { loadChaptersOfFeedItem(adapter, item); @@ -769,23 +574,21 @@ public final class DBReader { * Loads a specific FeedItem from the database. This method should not be used for loading more * than one FeedItem because this method might query the database several times for each item. * - * @param context A context that is used for opening a database connection. * @param itemId The ID of the FeedItem * @return The FeedItem or null if the FeedItem could not be found. All FeedComponent-attributes * as well as chapter marks of the FeedItem will also be loaded from the database. */ - public static FeedItem getFeedItem(final Context context, final long itemId) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Loading feeditem with id " + itemId); + public static FeedItem getFeedItem(final long itemId) { + Log.d(TAG, "Loading feeditem with id " + itemId); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - FeedItem item = getFeedItem(context, itemId, adapter); + FeedItem item = getFeedItem(itemId, adapter); adapter.close(); return item; } - static FeedItem getFeedItem(final Context context, final String podcastUrl, final String episodeUrl, PodDBAdapter adapter) { + static FeedItem getFeedItem(final String podcastUrl, final String episodeUrl, PodDBAdapter adapter) { Log.d(TAG, "Loading feeditem with podcast url " + podcastUrl + " and episode url " + episodeUrl); FeedItem item = null; Cursor itemCursor = adapter.getFeedItemCursor(podcastUrl, episodeUrl); @@ -793,7 +596,7 @@ public final class DBReader { List list = extractItemlistFromCursor(adapter, itemCursor); if (list.size() > 0) { item = list.get(0); - loadFeedDataOfFeedItemlist(context, list); + loadFeedDataOfFeedItemlist(list); if (item.hasChapters()) { loadChaptersOfFeedItem(adapter, item); } @@ -807,17 +610,16 @@ public final class DBReader { * Loads specific FeedItems from the database. This method canbe used for loading more * than one FeedItem * - * @param context A context that is used for opening a database connection. * @param itemIds The IDs of the FeedItems * @return The FeedItems or an empty list if none of the FeedItems could be found. All FeedComponent-attributes * as well as chapter marks of the FeedItems will also be loaded from the database. */ - public static List getFeedItems(final Context context, final long... itemIds) { + public static List getFeedItems(final long... itemIds) { Log.d(TAG, "Loading feeditem with ids: " + StringUtils.join(itemIds, ",")); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - List items = getFeedItems(context, adapter, itemIds); + List items = getFeedItems(adapter, itemIds); adapter.close(); return items; } @@ -826,22 +628,21 @@ public final class DBReader { /** * Returns credentials based on image URL * - * @param context A context that is used for opening a database connection. * @param imageUrl The URL of the image * @return Credentials in format ":", empty String if no authorization given */ - public static String getImageAuthentication(final Context context, final String imageUrl) { + public static String getImageAuthentication(final String imageUrl) { Log.d(TAG, "Loading credentials for image with URL " + imageUrl); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - String credentials = getImageAuthentication(context, imageUrl, adapter); + String credentials = getImageAuthentication(imageUrl, adapter); adapter.close(); return credentials; } - static String getImageAuthentication(final Context context, final String imageUrl, PodDBAdapter adapter) { + static String getImageAuthentication(final String imageUrl, PodDBAdapter adapter) { String credentials = null; Cursor cursor = adapter.getImageAuthenticationCursor(imageUrl); try { @@ -849,32 +650,33 @@ public final class DBReader { String username = cursor.getString(0); String password = cursor.getString(1); if(username != null && password != null) { - return username + ":" + password; + credentials = username + ":" + password; } else { - return ""; + credentials = ""; } + } else { + credentials = ""; } - return ""; } finally { cursor.close(); } + return credentials; } /** * Loads a specific FeedItem from the database. * - * @param context A context that is used for opening a database connection. * @param podcastUrl the corresponding feed's url * @param episodeUrl the feed item's url * @return The FeedItem or null if the FeedItem could not be found. All FeedComponent-attributes * as well as chapter marks of the FeedItem will also be loaded from the database. */ - public static FeedItem getFeedItem(final Context context, final String podcastUrl, final String episodeUrl) { + public static FeedItem getFeedItem(final String podcastUrl, final String episodeUrl) { Log.d(TAG, "Loading feeditem with podcast url " + podcastUrl + " and episode url " + episodeUrl); - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - FeedItem item = getFeedItem(context, podcastUrl, episodeUrl, adapter); + FeedItem item = getFeedItem(podcastUrl, episodeUrl, adapter); adapter.close(); return item; } @@ -882,18 +684,17 @@ public final class DBReader { /** * Loads additional information about a FeedItem, e.g. shownotes * - * @param context A context that is used for opening a database connection. * @param item The FeedItem */ - public static void loadExtraInformationOfFeedItem(final Context context, final FeedItem item) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static void loadExtraInformationOfFeedItem(final FeedItem item) { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor extraCursor = adapter.getExtraInformationOfItem(item); if (extraCursor.moveToFirst()) { - String description = extraCursor - .getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION); - String contentEncoded = extraCursor - .getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED); + int indexDescription = extraCursor.getColumnIndex(PodDBAdapter.KEY_DESCRIPTION); + String description = extraCursor.getString(indexDescription); + int indexContentEncoded = extraCursor.getColumnIndex(PodDBAdapter.KEY_CONTENT_ENCODED); + String contentEncoded = extraCursor.getString(indexContentEncoded); item.setDescription(description); item.setContentEncoded(contentEncoded); } @@ -906,31 +707,30 @@ public final class DBReader { * any chapters that this FeedItem has. If no chapters were found in the database, the chapters * reference of the FeedItem will be set to null. * - * @param context A context that is used for opening a database connection. * @param item The FeedItem */ - public static void loadChaptersOfFeedItem(final Context context, final FeedItem item) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static void loadChaptersOfFeedItem(final FeedItem item) { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); loadChaptersOfFeedItem(adapter, item); adapter.close(); } static void loadChaptersOfFeedItem(PodDBAdapter adapter, FeedItem item) { - Cursor chapterCursor = adapter - .getSimpleChaptersOfFeedItemCursor(item); + Cursor chapterCursor = adapter.getSimpleChaptersOfFeedItemCursor(item); if (chapterCursor.moveToFirst()) { - item.setChapters(new ArrayList()); + item.setChapters(new ArrayList<>()); do { - int chapterType = chapterCursor - .getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX); + int indexType = chapterCursor.getColumnIndex(PodDBAdapter.KEY_CHAPTER_TYPE); + int indexStart = chapterCursor.getColumnIndex(PodDBAdapter.KEY_START); + int indexTitle = chapterCursor.getColumnIndex(PodDBAdapter.KEY_TITLE); + int indexLink = chapterCursor.getColumnIndex(PodDBAdapter.KEY_LINK); + + int chapterType = chapterCursor.getInt(indexType); Chapter chapter = null; - long start = chapterCursor - .getLong(PodDBAdapter.KEY_CHAPTER_START_INDEX); - String title = chapterCursor - .getString(PodDBAdapter.KEY_TITLE_INDEX); - String link = chapterCursor - .getString(PodDBAdapter.KEY_CHAPTER_LINK_INDEX); + long start = chapterCursor.getLong(indexStart); + String title = chapterCursor.getString(indexTitle); + String link = chapterCursor.getString(indexLink); switch (chapterType) { case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: @@ -947,8 +747,8 @@ public final class DBReader { break; } if (chapter != null) { - chapter.setId(chapterCursor - .getLong(PodDBAdapter.KEY_ID_INDEX)); + int indexId = chapterCursor.getColumnIndex(PodDBAdapter.KEY_ID); + chapter.setId(chapterCursor.getLong(indexId)); item.getChapters().add(chapter); } } while (chapterCursor.moveToNext()); @@ -961,40 +761,24 @@ public final class DBReader { /** * Returns the number of downloaded episodes. * - * @param context A context that is used for opening a database connection. * @return The number of downloaded episodes. */ - public static int getNumberOfDownloadedEpisodes(final Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static int getNumberOfDownloadedEpisodes() { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); final int result = adapter.getNumberOfDownloadedEpisodes(); adapter.close(); return result; } - /** - * Returns the number of unread items. - * - * @param context A context that is used for opening a database connection. - * @return The number of unread items. - */ - public static int getNumberOfNewItems(final Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - final int result = adapter.getNumberOfNewItems(); - adapter.close(); - return result; - } - /** * Searches the DB for a FeedImage of the given id. * - * @param context A context that is used for opening a database connection. * @param imageId The id of the object * @return The found object */ - public static FeedImage getFeedImage(final Context context, final long imageId) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static FeedImage getFeedImage(final long imageId) { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); FeedImage result = getFeedImage(adapter, imageId); adapter.close(); @@ -1012,15 +796,8 @@ public final class DBReader { if ((cursor.getCount() == 0) || !cursor.moveToFirst()) { return null; } - FeedImage image = new FeedImage(id, cursor.getString(cursor - .getColumnIndex(PodDBAdapter.KEY_TITLE)), - cursor.getString(cursor - .getColumnIndex(PodDBAdapter.KEY_FILE_URL)), - cursor.getString(cursor - .getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL)), - cursor.getInt(cursor - .getColumnIndex(PodDBAdapter.KEY_DOWNLOADED)) > 0 - ); + FeedImage image = FeedImage.fromCursor(cursor); + image.setId(id); cursor.close(); return image; } @@ -1028,21 +805,21 @@ public final class DBReader { /** * Searches the DB for a FeedMedia of the given id. * - * @param context A context that is used for opening a database connection. * @param mediaId The id of the object * @return The found object */ - public static FeedMedia getFeedMedia(final Context context, final long mediaId) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static FeedMedia getFeedMedia(final long mediaId) { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor mediaCursor = adapter.getSingleFeedMediaCursor(mediaId); FeedMedia media = null; if (mediaCursor.moveToFirst()) { - final long itemId = mediaCursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX); - media = extractFeedMediaFromCursorRow(mediaCursor); - FeedItem item = getFeedItem(context, itemId); + int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); + final long itemId = mediaCursor.getLong(indexFeedItem); + media = FeedMedia.fromCursor(mediaCursor); + FeedItem item = getFeedItem(itemId); if (media != null && item != null) { media.setItem(item); item.setMedia(media); @@ -1058,13 +835,12 @@ public final class DBReader { /** * Returns the flattr queue as a List of FlattrThings. The list consists of Feeds and FeedItems. * - * @param context A context that is used for opening a database connection. * @return The flattr queue as a List. */ - public static List getFlattrQueue(Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static List getFlattrQueue() { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - List result = new ArrayList(); + List result = new ArrayList<>(); // load feeds Cursor feedCursor = adapter.getFeedsInFlattrQueueCursor(); @@ -1085,29 +861,14 @@ public final class DBReader { return result; } - - /** - * Returns true if the flattr queue is empty. - * - * @param context A context that is used for opening a database connection. - */ - public static boolean getFlattrQueueEmpty(Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - boolean empty = adapter.getFlattrQueueSize() == 0; - adapter.close(); - return empty; - } - /** * Returns data necessary for displaying the navigation drawer. This includes * the list of subscriptions, the number of items in the queue and the number of unread * items. * - * @param context A context that is used for opening a database connection. */ - public static NavDrawerData getNavDrawerData(Context context) { - PodDBAdapter adapter = new PodDBAdapter(context); + public static NavDrawerData getNavDrawerData() { + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); List feeds = getFeedList(adapter); long[] feedIds = new long[feeds.size()]; @@ -1119,30 +880,24 @@ public final class DBReader { Comparator comparator; int feedOrder = UserPreferences.getFeedOrder(); if(feedOrder == UserPreferences.FEED_ORDER_COUNTER) { - comparator = new Comparator() { - @Override - public int compare(Feed lhs, Feed rhs) { - long counterLhs = feedCounters.get(lhs.getId()); - long counterRhs = feedCounters.get(rhs.getId()); - if(counterLhs > counterRhs) { - // reverse natural order: podcast with most unplayed episodes first - return -1; - } else if(counterLhs == counterRhs) { - return lhs.getTitle().compareTo(rhs.getTitle()); - } else { - return 1; - } + comparator = (lhs, rhs) -> { + long counterLhs = feedCounters.get(lhs.getId()); + long counterRhs = feedCounters.get(rhs.getId()); + if(counterLhs > counterRhs) { + // reverse natural order: podcast with most unplayed episodes first + return -1; + } else if(counterLhs == counterRhs) { + return lhs.getTitle().compareTo(rhs.getTitle()); + } else { + return 1; } }; } else { - comparator = new Comparator() { - @Override - public int compare(Feed lhs, Feed rhs) { - if(lhs.getTitle() == null) { - return 1; - } - return lhs.getTitle().compareTo(rhs.getTitle()); + comparator = (lhs, rhs) -> { + if(lhs.getTitle() == null) { + return 1; } + return lhs.getTitle().compareTo(rhs.getTitle()); }; } 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 6ed99ec41..96a632d68 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 @@ -68,7 +68,7 @@ public final class DBTasks { * @param downloadUrl URL of the feed. */ public static void removeFeedWithDownloadUrl(Context context, String downloadUrl) { - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); Cursor cursor = adapter.getFeedCursorDownloadUrls(); long feedID = 0; @@ -163,7 +163,7 @@ public final class DBTasks { if (feeds != null) { refreshFeeds(context, feeds); } else { - refreshFeeds(context, DBReader.getFeedList(context)); + refreshFeeds(context, DBReader.getFeedList()); } isRefreshing.set(false); @@ -196,7 +196,6 @@ public final class DBTasks { } catch (DownloadRequestException e) { e.printStackTrace(); DBWriter.addDownloadStatus( - context, new DownloadStatus(feed, feed .getHumanReadableIdentifier(), DownloadError.ERROR_REQUEST_ERROR, false, e @@ -220,7 +219,6 @@ public final class DBTasks { } catch (DownloadRequestException e) { e.printStackTrace(); DBWriter.addDownloadStatus( - context, new DownloadStatus(feed, feed .getHumanReadableIdentifier(), DownloadError.ERROR_REQUEST_ERROR, false, e @@ -287,7 +285,7 @@ public final class DBTasks { "The feedmanager was notified about a missing episode. It will update its database now."); media.setDownloaded(false); media.setFile_url(null); - DBWriter.setFeedMedia(context, media); + DBWriter.setFeedMedia(media); EventDistributor.getInstance().sendFeedUpdateBroadcast(); } @@ -299,7 +297,7 @@ public final class DBTasks { public static void downloadAllItemsInQueue(final Context context) { new Thread() { public void run() { - List queue = DBReader.getQueue(context); + List queue = DBReader.getQueue(); if (!queue.isEmpty()) { try { downloadFeedItems(context, @@ -336,7 +334,7 @@ public final class DBTasks { ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm() .performCleanup(context, ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm() - .getPerformCleanupParameter(context, Arrays.asList(items))); + .getPerformCleanupParameter(Arrays.asList(items))); } }.start(); @@ -350,7 +348,7 @@ public final class DBTasks { requester.downloadMedia(context, item.getMedia()); } catch (DownloadRequestException e) { e.printStackTrace(); - DBWriter.addDownloadStatus(context, + DBWriter.addDownloadStatus( new DownloadStatus(item.getMedia(), item .getMedia() .getHumanReadableIdentifier(), @@ -393,7 +391,7 @@ public final class DBTasks { */ public static void performAutoCleanup(final Context context) { ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm().performCleanup(context, - ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm().getDefaultCleanupParameter(context)); + ClientConfig.dbTasksCallbacks.getEpisodeCacheCleanupAlgorithm().getDefaultCleanupParameter()); } /** @@ -409,7 +407,7 @@ public final class DBTasks { final long itemId, List queue) { FeedItem result = null; if (queue == null) { - queue = DBReader.getQueue(context); + queue = DBReader.getQueue(); } if (queue != null) { Iterator iterator = queue.iterator(); @@ -434,19 +432,19 @@ public final class DBTasks { * @param feedItemId ID of the FeedItem */ public static boolean isInQueue(Context context, final long feedItemId) { - LongList queue = DBReader.getQueueIDList(context); + LongList queue = DBReader.getQueueIDList(); return queue.contains(feedItemId); } private static Feed searchFeedByIdentifyingValueOrID(Context context, PodDBAdapter adapter, Feed feed) { if (feed.getId() != 0) { - return DBReader.getFeed(context, feed.getId(), adapter); + return DBReader.getFeed(feed.getId(), adapter); } else { - List feeds = DBReader.getFeedList(context); + List feeds = DBReader.getFeedList(); for (Feed f : feeds) { if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) { - f.setItems(DBReader.getFeedItemList(context, f)); + f.setItems(DBReader.getFeedItemList(f)); return f; } } @@ -485,7 +483,7 @@ public final class DBTasks { List newFeedsList = new ArrayList(); List updatedFeedsList = new ArrayList(); Feed[] resultFeeds = new Feed[newFeeds.length]; - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); for (int feedIdx = 0; feedIdx < newFeeds.length; feedIdx++) { @@ -574,7 +572,7 @@ public final class DBTasks { try { DBWriter.addNewFeed(context, newFeedsList.toArray(new Feed[newFeedsList.size()])).get(); - DBWriter.setCompleteFeed(context, updatedFeedsList.toArray(new Feed[updatedFeedsList.size()])).get(); + DBWriter.setCompleteFeed(updatedFeedsList.toArray(new Feed[updatedFeedsList.size()])).get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { @@ -602,8 +600,8 @@ public final class DBTasks { public void execute(PodDBAdapter adapter) { Cursor searchResult = adapter.searchItemTitles(feedID, query); - List items = DBReader.extractItemlistFromCursor(context, searchResult); - DBReader.loadFeedDataOfFeedItemlist(context, items); + List items = DBReader.extractItemlistFromCursor(searchResult); + DBReader.loadFeedDataOfFeedItemlist(items); setResult(items); searchResult.close(); } @@ -626,8 +624,8 @@ public final class DBTasks { public void execute(PodDBAdapter adapter) { Cursor searchResult = adapter.searchItemDescriptions(feedID, query); - List items = DBReader.extractItemlistFromCursor(context, searchResult); - DBReader.loadFeedDataOfFeedItemlist(context, items); + List items = DBReader.extractItemlistFromCursor(searchResult); + DBReader.loadFeedDataOfFeedItemlist(items); setResult(items); searchResult.close(); } @@ -650,8 +648,8 @@ public final class DBTasks { public void execute(PodDBAdapter adapter) { Cursor searchResult = adapter.searchItemContentEncoded(feedID, query); - List items = DBReader.extractItemlistFromCursor(context, searchResult); - DBReader.loadFeedDataOfFeedItemlist(context, items); + List items = DBReader.extractItemlistFromCursor(searchResult); + DBReader.loadFeedDataOfFeedItemlist(items); setResult(items); searchResult.close(); } @@ -673,8 +671,8 @@ public final class DBTasks { public void execute(PodDBAdapter adapter) { Cursor searchResult = adapter.searchItemChapters(feedID, query); - List items = DBReader.extractItemlistFromCursor(context, searchResult); - DBReader.loadFeedDataOfFeedItemlist(context, items); + List items = DBReader.extractItemlistFromCursor(searchResult); + DBReader.loadFeedDataOfFeedItemlist(items); setResult(items); searchResult.close(); } @@ -697,7 +695,7 @@ public final class DBTasks { @Override public T call() throws Exception { - PodDBAdapter adapter = new PodDBAdapter(context); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); execute(adapter); adapter.close(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index 0f7065c59..521f960ec 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -22,7 +22,6 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.ClientConfig; @@ -56,19 +55,16 @@ import de.greenrobot.event.EventBus; * This class will use the {@link EventDistributor} to notify listeners about changes in the database. */ public class DBWriter { + private static final String TAG = "DBWriter"; private static final ExecutorService dbExec; static { - dbExec = Executors.newSingleThreadExecutor(new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } + dbExec = Executors.newSingleThreadExecutor(r -> { + Thread t = new Thread(r); + t.setPriority(Thread.MIN_PRIORITY); + return t; }); } @@ -83,63 +79,59 @@ public class DBWriter { */ public static Future deleteFeedMediaOfItem(final Context context, final long mediaId) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - - final FeedMedia media = DBReader.getFeedMedia(context, mediaId); - if (media != null) { - Log.i(TAG, String.format("Requested to delete FeedMedia [id=%d, title=%s, downloaded=%s", - media.getId(), media.getEpisodeTitle(), String.valueOf(media.isDownloaded()))); - boolean result = false; - if (media.isDownloaded()) { - // delete downloaded media file - File mediaFile = new File(media.getFile_url()); - if (mediaFile.exists()) { - result = mediaFile.delete(); - } - media.setDownloaded(false); - media.setFile_url(null); - media.setHasEmbeddedPicture(false); - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setMedia(media); - adapter.close(); - - // If media is currently being played, change playback - // type to 'stream' and shutdown playback service - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(context); - if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) { - if (media.getId() == PlaybackPreferences - .getCurrentlyPlayingFeedMediaId()) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean( - PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM, - true); - editor.commit(); - } - if (PlaybackPreferences - .getCurrentlyPlayingFeedMediaId() == media - .getId()) { - context.sendBroadcast(new Intent( - PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); - } + return dbExec.submit(() -> { + final FeedMedia media = DBReader.getFeedMedia(mediaId); + if (media != null) { + Log.i(TAG, String.format("Requested to delete FeedMedia [id=%d, title=%s, downloaded=%s", + media.getId(), media.getEpisodeTitle(), String.valueOf(media.isDownloaded()))); + boolean result = false; + if (media.isDownloaded()) { + // delete downloaded media file + File mediaFile = new File(media.getFile_url()); + if (mediaFile.exists()) { + result = mediaFile.delete(); + } + media.setDownloaded(false); + media.setFile_url(null); + media.setHasEmbeddedPicture(false); + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setMedia(media); + adapter.close(); + + // If media is currently being played, change playback + // type to 'stream' and shutdown playback service + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(context); + if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) { + if (media.getId() == PlaybackPreferences + .getCurrentlyPlayingFeedMediaId()) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean( + PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM, + true); + editor.commit(); } - // Gpodder: queue delete action for synchronization - if(GpodnetPreferences.loggedIn()) { - FeedItem item = media.getItem(); - GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, GpodnetEpisodeAction.Action.DELETE) - .currentDeviceId() - .currentTimestamp() - .build(); - GpodnetPreferences.enqueueEpisodeAction(action); + if (PlaybackPreferences + .getCurrentlyPlayingFeedMediaId() == media + .getId()) { + context.sendBroadcast(new Intent( + PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); } } - Log.d(TAG, "Deleting File. Result: " + result); - EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.DELETED_MEDIA, media.getItem())); - EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); + // Gpodder: queue delete action for synchronization + if(GpodnetPreferences.loggedIn()) { + FeedItem item = media.getItem(); + GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, GpodnetEpisodeAction.Action.DELETE) + .currentDeviceId() + .currentTimestamp() + .build(); + GpodnetPreferences.enqueueEpisodeAction(action); + } } + Log.d(TAG, "Deleting File. Result: " + result); + EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.DELETED_MEDIA, media.getItem())); + EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); } }); } @@ -151,87 +143,85 @@ public class DBWriter { * @param feedId ID of the Feed that should be deleted. */ public static Future deleteFeed(final Context context, final long feedId) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - DownloadRequester requester = DownloadRequester.getInstance(); - SharedPreferences prefs = PreferenceManager - .getDefaultSharedPreferences(context - .getApplicationContext()); - final Feed feed = DBReader.getFeed(context, feedId); - if (feed != null) { - if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA - && PlaybackPreferences.getLastPlayedFeedId() == feed - .getId()) { - context.sendBroadcast(new Intent( - PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); - SharedPreferences.Editor editor = prefs.edit(); - editor.putLong( - PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, - -1); - editor.commit(); - } + return dbExec.submit(() -> { + DownloadRequester requester = DownloadRequester.getInstance(); + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(context + .getApplicationContext()); + final Feed feed = DBReader.getFeed(feedId); + + if (feed != null) { + if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA + && PlaybackPreferences.getLastPlayedFeedId() == feed + .getId()) { + context.sendBroadcast(new Intent( + PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); + SharedPreferences.Editor editor = prefs.edit(); + editor.putLong( + PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, + -1); + editor.commit(); + } - // delete image file - if (feed.getImage() != null) { - if (feed.getImage().isDownloaded() - && feed.getImage().getFile_url() != null) { - File imageFile = new File(feed.getImage() - .getFile_url()); - imageFile.delete(); - } else if (requester.isDownloadingFile(feed.getImage())) { - requester.cancelDownload(context, feed.getImage()); - } - } - // delete stored media files and mark them as read - List queue = DBReader.getQueue(context); - List removed = new ArrayList<>(); - if (feed.getItems() == null) { - DBReader.getFeedItemList(context, feed); + // delete image file + if (feed.getImage() != null) { + if (feed.getImage().isDownloaded() + && feed.getImage().getFile_url() != null) { + File imageFile = new File(feed.getImage() + .getFile_url()); + imageFile.delete(); + } else if (requester.isDownloadingFile(feed.getImage())) { + requester.cancelDownload(context, feed.getImage()); } + } + // delete stored media files and mark them as read + List queue = DBReader.getQueue(); + List removed = new ArrayList<>(); + if (feed.getItems() == null) { + DBReader.getFeedItemList(feed); + } - for (FeedItem item : feed.getItems()) { - if(queue.remove(item)) { - removed.add(item); - } - if (item.getMedia() != null - && item.getMedia().isDownloaded()) { - File mediaFile = new File(item.getMedia() - .getFile_url()); - mediaFile.delete(); - } else if (item.getMedia() != null - && requester.isDownloadingFile(item.getMedia())) { - requester.cancelDownload(context, item.getMedia()); - } - - if (item.hasItemImage()) { - FeedImage image = item.getImage(); - if (image.isDownloaded() && image.getFile_url() != null) { - File imgFile = new File(image.getFile_url()); - imgFile.delete(); - } else if (requester.isDownloadingFile(image)) { - requester.cancelDownload(context, item.getImage()); - } - } + for (FeedItem item : feed.getItems()) { + if(queue.remove(item)) { + removed.add(item); } - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - if (removed.size() > 0) { - adapter.setQueue(queue); - EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.IRREVERSIBLE_REMOVED, - removed)); + if (item.getMedia() != null + && item.getMedia().isDownloaded()) { + File mediaFile = new File(item.getMedia() + .getFile_url()); + mediaFile.delete(); + } else if (item.getMedia() != null + && requester.isDownloadingFile(item.getMedia())) { + requester.cancelDownload(context, item.getMedia()); } - adapter.removeFeed(feed); - adapter.close(); - if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { - GpodnetPreferences.addRemovedFeed(feed.getDownload_url()); + if (item.hasItemImage()) { + FeedImage image = item.getImage(); + if (image.isDownloaded() && image.getFile_url() != null) { + File imgFile = new File(image.getFile_url()); + imgFile.delete(); + } else if (requester.isDownloadingFile(image)) { + requester.cancelDownload(context, item.getImage()); + } } - EventDistributor.getInstance().sendFeedUpdateBroadcast(); + } + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + if (removed.size() > 0) { + adapter.setQueue(queue); + EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.IRREVERSIBLE_REMOVED, + removed)); + } + adapter.removeFeed(feed); + adapter.close(); - BackupManager backupManager = new BackupManager(context); - backupManager.dataChanged(); + if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { + GpodnetPreferences.addRemovedFeed(feed.getDownload_url()); } + EventDistributor.getInstance().sendFeedUpdateBroadcast(); + + BackupManager backupManager = new BackupManager(context); + backupManager.dataChanged(); } }); } @@ -239,39 +229,27 @@ public class DBWriter { /** * Deletes the entire playback history. * - * @param context A context that is used for opening a database connection. */ - public static Future clearPlaybackHistory(final Context context) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.clearPlaybackHistory(); - adapter.close(); - EventDistributor.getInstance() - .sendPlaybackHistoryUpdateBroadcast(); - } + public static Future clearPlaybackHistory() { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.clearPlaybackHistory(); + adapter.close(); + EventDistributor.getInstance().sendPlaybackHistoryUpdateBroadcast(); }); } /** * Deletes the entire download log. - * - * @param context A context that is used for opening a database connection. */ - public static Future clearDownloadLog(final Context context) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.clearDownloadLog(); - adapter.close(); - EventDistributor.getInstance() - .sendDownloadLogUpdateBroadcast(); - } + public static Future clearDownloadLog() { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.clearDownloadLog(); + adapter.close(); + EventDistributor.getInstance().sendDownloadLogUpdateBroadcast(); }); } @@ -281,58 +259,36 @@ public class DBWriter { * its playback completion date is set to a non-null value. This method will set the playback completion date to the * current date regardless of the current value. * - * @param context A context that is used for opening a database connection. * @param media FeedMedia that should be added to the playback history. */ - public static Future addItemToPlaybackHistory(final Context context, - final FeedMedia media) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - if (BuildConfig.DEBUG) - Log.d(TAG, "Adding new item to playback history"); - media.setPlaybackCompletionDate(new Date()); - // reset played_duration to 0 so that it behaves correctly when the episode is played again - media.setPlayedDuration(0); + public static Future addItemToPlaybackHistory(final FeedMedia media) { + return dbExec.submit(() -> { + Log.d(TAG, "Adding new item to playback history"); + media.setPlaybackCompletionDate(new Date()); + // reset played_duration to 0 so that it behaves correctly when the episode is played again + media.setPlayedDuration(0); - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedMediaPlaybackCompletionDate(media); - adapter.close(); - EventDistributor.getInstance().sendPlaybackHistoryUpdateBroadcast(); + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedMediaPlaybackCompletionDate(media); + adapter.close(); + EventDistributor.getInstance().sendPlaybackHistoryUpdateBroadcast(); - } }); } - private static void cleanupDownloadLog(final PodDBAdapter adapter) { - final long logSize = adapter.getDownloadLogSize(); - if (logSize > DBReader.DOWNLOAD_LOG_SIZE) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Cleaning up download log"); - adapter.removeDownloadLogItems(logSize - DBReader.DOWNLOAD_LOG_SIZE); - } - } - /** * Adds a Download status object to the download log. * - * @param context A context that is used for opening a database connection. * @param status The DownloadStatus object. */ - public static Future addDownloadStatus(final Context context, - final DownloadStatus status) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setDownloadStatus(status); - adapter.close(); - EventDistributor.getInstance().sendDownloadLogUpdateBroadcast(); - } + public static Future addDownloadStatus(final DownloadStatus status) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setDownloadStatus(status); + adapter.close(); + EventDistributor.getInstance().sendDownloadLogUpdateBroadcast(); }); } @@ -349,35 +305,31 @@ public class DBWriter { */ public static Future addQueueItemAt(final Context context, final long itemId, final int index, final boolean performAutoDownload) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - final List queue = DBReader.getQueue(context, adapter); - FeedItem item; - - if (queue != null) { - if (!itemListContains(queue, itemId)) { - item = DBReader.getFeedItem(context, itemId); - if (item != null) { - queue.add(index, item); - adapter.setQueue(queue); - EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.ADDED, item, index)); - if(item.isNew()) { - DBWriter.markItemPlayed(context, FeedItem.UNPLAYED, item.getId()); - } + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + final List queue = DBReader.getQueue(adapter); + FeedItem item; + + if (queue != null) { + if (!itemListContains(queue, itemId)) { + item = DBReader.getFeedItem(itemId); + if (item != null) { + queue.add(index, item); + adapter.setQueue(queue); + EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.ADDED, item, index)); + if (item.isNew()) { + DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId()); } } } + } - adapter.close(); - if (performAutoDownload) { - DBTasks.autodownloadUndownloadedItems(context); - } - + adapter.close(); + if (performAutoDownload) { + DBTasks.autodownloadUndownloadedItems(context); } + }); } @@ -397,50 +349,46 @@ public class DBWriter { */ public static Future addQueueItem(final Context context, final boolean performAutoDownload, final long... itemIds) { - return dbExec.submit(new Runnable() { + return dbExec.submit(() -> { + if (itemIds.length > 0) { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + final List queue = DBReader.getQueue(adapter); - @Override - public void run() { - if (itemIds.length > 0) { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - final List queue = DBReader.getQueue(context, adapter); - - if (queue != null) { - boolean queueModified = false; - LongList markAsUnplayedIds = new LongList(); - for (int i = 0; i < itemIds.length; i++) { - if (!itemListContains(queue, itemIds[i])) { - final FeedItem item = DBReader.getFeedItem(context, itemIds[i]); - - if (item != null) { - // add item to either front ot back of queue - boolean addToFront = UserPreferences.enqueueAtFront(); - if (addToFront) { - queue.add(0 + i, item); - } else { - queue.add(item); - } - queueModified = true; - if(item.isNew()) { - markAsUnplayedIds.add(item.getId()); - } + if (queue != null) { + boolean queueModified = false; + LongList markAsUnplayedIds = new LongList(); + for (int i = 0; i < itemIds.length; i++) { + if (!itemListContains(queue, itemIds[i])) { + final FeedItem item = DBReader.getFeedItem(itemIds[i]); + + if (item != null) { + // add item to either front ot back of queue + boolean addToFront = UserPreferences.enqueueAtFront(); + if (addToFront) { + queue.add(0 + i, item); + } else { + queue.add(item); + } + queueModified = true; + if(item.isNew()) { + markAsUnplayedIds.add(item.getId()); } - } - } - if (queueModified) { - adapter.setQueue(queue); - EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.ADDED_ITEMS, queue)); - if(markAsUnplayedIds.size() > 0) { - DBWriter.markItemPlayed(context, FeedItem.UNPLAYED, markAsUnplayedIds.toArray()); } } } - adapter.close(); - if (performAutoDownload) { - DBTasks.autodownloadUndownloadedItems(context); + if (queueModified) { + adapter.setQueue(queue); + EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.ADDED_ITEMS, queue)); + if(markAsUnplayedIds.size() > 0) { + DBWriter.markItemPlayed(FeedItem.UNPLAYED, markAsUnplayedIds.toArray()); + } } } + adapter.close(); + if (performAutoDownload) { + DBTasks.autodownloadUndownloadedItems(context); + } } }); } @@ -448,20 +396,15 @@ public class DBWriter { /** * Removes all FeedItem objects from the queue. * - * @param context A context that is used for opening a database connection. */ - public static Future clearQueue(final Context context) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.clearQueue(); - adapter.close(); + public static Future clearQueue() { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.clearQueue(); + adapter.close(); - EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.CLEARED)); - } + EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.CLEARED)); }); } @@ -474,30 +417,26 @@ public class DBWriter { */ public static Future removeQueueItem(final Context context, final FeedItem item, final boolean performAutoDownload) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - final List queue = DBReader.getQueue(context, adapter); + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + final List queue = DBReader.getQueue(adapter); - if (queue != null) { - int position = queue.indexOf(item); - if(position >= 0) { - queue.remove(position); - adapter.setQueue(queue); - EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.REMOVED, item, position)); - } else { - Log.w(TAG, "Queue was not modified by call to removeQueueItem"); - } + if (queue != null) { + int position = queue.indexOf(item); + if(position >= 0) { + queue.remove(position); + adapter.setQueue(queue); + EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.REMOVED, item, position)); } else { - Log.e(TAG, "removeQueueItem: Could not load queue"); - } - adapter.close(); - if (performAutoDownload) { - DBTasks.autodownloadUndownloadedItems(context); + Log.w(TAG, "Queue was not modified by call to removeQueueItem"); } + } else { + Log.e(TAG, "removeQueueItem: Could not load queue"); + } + adapter.close(); + if (performAutoDownload) { + DBTasks.autodownloadUndownloadedItems(context); } }); @@ -505,48 +444,36 @@ public class DBWriter { /** * Moves the specified item to the top of the queue. - * - * @param context A context that is used for opening a database connection. - * @param itemId The item to move to the top of the queue + * @param itemId The item to move to the top of the queue * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to - * false if the caller wants to avoid unexpected updates of the GUI. */ - public static Future moveQueueItemToTop(final Context context, final long itemId, final boolean broadcastUpdate) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - LongList queueIdList = DBReader.getQueueIDList(context); - int index = queueIdList.indexOf(itemId); - if (index >=0) { - moveQueueItemHelper(context, index, 0, broadcastUpdate); - } else { - Log.e(TAG, "moveQueueItemToTop: item not found"); - } + public static Future moveQueueItemToTop(final long itemId, final boolean broadcastUpdate) { + return dbExec.submit(() -> { + LongList queueIdList = DBReader.getQueueIDList(); + int index = queueIdList.indexOf(itemId); + if (index >=0) { + moveQueueItemHelper(index, 0, broadcastUpdate); + } else { + Log.e(TAG, "moveQueueItemToTop: item not found"); } }); } /** * Moves the specified item to the bottom of the queue. - * - * @param context A context that is used for opening a database connection. - * @param itemId The item to move to the bottom of the queue + * @param itemId The item to move to the bottom of the queue * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to - * false if the caller wants to avoid unexpected updates of the GUI. */ - public static Future moveQueueItemToBottom(final Context context, final long itemId, + public static Future moveQueueItemToBottom(final long itemId, final boolean broadcastUpdate) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - LongList queueIdList = DBReader.getQueueIDList(context); - int index = queueIdList.indexOf(itemId); - if(index >= 0) { - moveQueueItemHelper(context, index, queueIdList.size() - 1, - broadcastUpdate); - } else { - Log.e(TAG, "moveQueueItemToBottom: item not found"); - } + return dbExec.submit(() -> { + LongList queueIdList = DBReader.getQueueIDList(); + int index = queueIdList.indexOf(itemId); + if(index >= 0) { + moveQueueItemHelper(index, queueIdList.size() - 1, + broadcastUpdate); + } else { + Log.e(TAG, "moveQueueItemToBottom: item not found"); } }); } @@ -554,21 +481,16 @@ public class DBWriter { /** * Changes the position of a FeedItem in the queue. * - * @param context A context that is used for opening a database connection. * @param from Source index. Must be in range 0..queue.size()-1. * @param to Destination index. Must be in range 0..queue.size()-1. * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to * false if the caller wants to avoid unexpected updates of the GUI. * @throws IndexOutOfBoundsException if (to < 0 || to >= queue.size()) || (from < 0 || from >= queue.size()) */ - public static Future moveQueueItem(final Context context, final int from, + public static Future moveQueueItem(final int from, final int to, final boolean broadcastUpdate) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - moveQueueItemHelper(context, from, to, broadcastUpdate); - } + return dbExec.submit(() -> { + moveQueueItemHelper(from, to, broadcastUpdate); }); } @@ -577,24 +499,20 @@ public class DBWriter { *

* This function must be run using the ExecutorService (dbExec). * - * @param context A context that is used for opening a database connection. * @param from Source index. Must be in range 0..queue.size()-1. * @param to Destination index. Must be in range 0..queue.size()-1. * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to * false if the caller wants to avoid unexpected updates of the GUI. * @throws IndexOutOfBoundsException if (to < 0 || to >= queue.size()) || (from < 0 || from >= queue.size()) */ - private static void moveQueueItemHelper(final Context context, final int from, + private static void moveQueueItemHelper(final int from, final int to, final boolean broadcastUpdate) { - final PodDBAdapter adapter = new PodDBAdapter(context); + final PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - final List queue = DBReader - .getQueue(context, adapter); + final List queue = DBReader.getQueue(adapter); if (queue != null) { - if (from >= 0 && from < queue.size() && to >= 0 - && to < queue.size()) { - + if (from >= 0 && from < queue.size() && to >= 0 && to < queue.size()) { final FeedItem item = queue.remove(from); queue.add(to, item); @@ -602,7 +520,6 @@ public class DBWriter { if (broadcastUpdate) { EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.MOVED, item, to)); } - } } else { Log.e(TAG, "moveQueueItemHelper: Could not load queue"); @@ -618,9 +535,9 @@ public class DBWriter { * FeedItem.UNPLAYED * @param itemIds IDs of the FeedItems. */ - public static Future markItemPlayed(final Context context, final int played, final long... itemIds) { + public static Future markItemPlayed(final int played, final long... itemIds) { return dbExec.submit(() -> { - final PodDBAdapter adapter = new PodDBAdapter(context); + final PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); adapter.setFeedItemRead(played, itemIds); adapter.close(); @@ -631,24 +548,22 @@ public class DBWriter { /** * Sets the 'read'-attribute of a FeedItem to the specified value. - * - * @param context A context that is used for opening a database connection. - * @param item The FeedItem object + * @param item The FeedItem object * @param played New value of the 'read'-attribute one of FeedItem.PLAYED, * FeedItem.NEW, FeedItem.UNPLAYED * @param resetMediaPosition true if this method should also reset the position of the FeedItem's FeedMedia object. - * If the FeedItem has no FeedMedia object, this parameter will be ignored. */ - public static Future markItemPlayed(Context context, FeedItem item, int played, boolean resetMediaPosition) { + public static Future markItemPlayed(FeedItem item, int played, boolean resetMediaPosition) { long mediaId = (item.hasMedia()) ? item.getMedia().getId() : 0; - return markItemPlayed(context, item.getId(), played, mediaId, resetMediaPosition); + return markItemPlayed(item.getId(), played, mediaId, resetMediaPosition); } - private static Future markItemPlayed(final Context context, final long itemId, - final int played, final long mediaId, + private static Future markItemPlayed(final long itemId, + final int played, + final long mediaId, final boolean resetMediaPosition) { return dbExec.submit(() -> { - final PodDBAdapter adapter = new PodDBAdapter(context); + final PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); adapter.setFeedItemRead(played, itemId, mediaId, resetMediaPosition); @@ -661,163 +576,129 @@ public class DBWriter { /** * Sets the 'read'-attribute of all FeedItems of a specific Feed to true. * - * @param context A context that is used for opening a database connection. * @param feedId ID of the Feed. */ - public static Future markFeedSeen(final Context context, final long feedId) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - Cursor itemCursor = adapter.getNewItemsIdsCursor(feedId); - long[] ids = new long[itemCursor.getCount()]; - itemCursor.moveToFirst(); - for (int i = 0; i < ids.length; i++) { - ids[i] = itemCursor.getLong(0); - itemCursor.moveToNext(); - } - itemCursor.close(); - adapter.setFeedItemRead(FeedItem.UNPLAYED, ids); - adapter.close(); + public static Future markFeedSeen(final long feedId) { + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + Cursor itemCursor = adapter.getNewItemsIdsCursor(feedId); + long[] ids = new long[itemCursor.getCount()]; + itemCursor.moveToFirst(); + for (int i = 0; i < ids.length; i++) { + ids[i] = itemCursor.getLong(0); + itemCursor.moveToNext(); + } + itemCursor.close(); + adapter.setFeedItemRead(FeedItem.UNPLAYED, ids); + adapter.close(); - EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); - } + EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); }); } /** * Sets the 'read'-attribute of all FeedItems of a specific Feed to true. * - * @param context A context that is used for opening a database connection. * @param feedId ID of the Feed. */ - public static Future markFeedRead(final Context context, final long feedId) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - Cursor itemCursor = adapter.getAllItemsOfFeedCursor(feedId); - long[] itemIds = new long[itemCursor.getCount()]; - itemCursor.moveToFirst(); - for (int i = 0; i < itemIds.length; i++) { - itemIds[i] = itemCursor.getLong(PodDBAdapter.KEY_ID_INDEX); - itemCursor.moveToNext(); - } - itemCursor.close(); - adapter.setFeedItemRead(FeedItem.PLAYED, itemIds); - adapter.close(); + public static Future markFeedRead(final long feedId) { + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + Cursor itemCursor = adapter.getAllItemsOfFeedCursor(feedId); + long[] itemIds = new long[itemCursor.getCount()]; + itemCursor.moveToFirst(); + for (int i = 0; i < itemIds.length; i++) { + int indexId = itemCursor.getColumnIndex(PodDBAdapter.KEY_ID); + itemIds[i] = itemCursor.getLong(indexId); + itemCursor.moveToNext(); + } + itemCursor.close(); + adapter.setFeedItemRead(FeedItem.PLAYED, itemIds); + adapter.close(); - EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); - } + EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); }); } /** * Sets the 'read'-attribute of all FeedItems to true. - * - * @param context A context that is used for opening a database connection. */ - public static Future markAllItemsRead(final Context context) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - Cursor itemCursor = adapter.getUnreadItemsCursor(); - long[] itemIds = new long[itemCursor.getCount()]; - itemCursor.moveToFirst(); - for (int i = 0; i < itemIds.length; i++) { - itemIds[i] = itemCursor.getLong(PodDBAdapter.KEY_ID_INDEX); - itemCursor.moveToNext(); - } - itemCursor.close(); - adapter.setFeedItemRead(FeedItem.PLAYED, itemIds); - adapter.close(); + public static Future markAllItemsRead() { + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + Cursor itemCursor = adapter.getUnreadItemsCursor(); + long[] itemIds = new long[itemCursor.getCount()]; + itemCursor.moveToFirst(); + for (int i = 0; i < itemIds.length; i++) { + int indexId = itemCursor.getColumnIndex(PodDBAdapter.KEY_ID); + itemIds[i] = itemCursor.getLong(indexId); + itemCursor.moveToNext(); + } + itemCursor.close(); + adapter.setFeedItemRead(FeedItem.PLAYED, itemIds); + adapter.close(); - EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); - } + EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); }); } static Future addNewFeed(final Context context, final Feed... feeds) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setCompleteFeed(feeds); - adapter.close(); + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setCompleteFeed(feeds); + adapter.close(); - if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { - for (Feed feed : feeds) { - GpodnetPreferences.addAddedFeed(feed.getDownload_url()); - } + if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { + for (Feed feed : feeds) { + GpodnetPreferences.addAddedFeed(feed.getDownload_url()); } - - BackupManager backupManager = new BackupManager(context); - backupManager.dataChanged(); } + + BackupManager backupManager = new BackupManager(context); + backupManager.dataChanged(); }); } - static Future setCompleteFeed(final Context context, final Feed... feeds) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setCompleteFeed(feeds); - adapter.close(); - - } + static Future setCompleteFeed(final Feed... feeds) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setCompleteFeed(feeds); + adapter.close(); }); - } /** * Saves a FeedMedia object in the database. This method will save all attributes of the FeedMedia object. The * contents of FeedComponent-attributes (e.g. the FeedMedia's 'item'-attribute) will not be saved. * - * @param context A context that is used for opening a database connection. * @param media The FeedMedia object. */ - public static Future setFeedMedia(final Context context, - final FeedMedia media) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setMedia(media); - adapter.close(); - } + public static Future setFeedMedia(final FeedMedia media) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setMedia(media); + adapter.close(); }); } /** * Saves the 'position' and 'duration' attributes of a FeedMedia object * - * @param context A context that is used for opening a database connection. * @param media The FeedMedia object. */ - public static Future setFeedMediaPlaybackInformation(final Context context, final FeedMedia media) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedMediaPlaybackInformation(media); - adapter.close(); - } + public static Future setFeedMediaPlaybackInformation(final FeedMedia media) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedMediaPlaybackInformation(media); + adapter.close(); }); } @@ -825,20 +706,14 @@ public class DBWriter { * Saves a FeedItem object in the database. This method will save all attributes of the FeedItem object including * the content of FeedComponent-attributes. * - * @param context A context that is used for opening a database connection. * @param item The FeedItem object. */ - public static Future setFeedItem(final Context context, - final FeedItem item) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setSingleFeedItem(item); - adapter.close(); - } + public static Future setFeedItem(final FeedItem item) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setSingleFeedItem(item); + adapter.close(); }); } @@ -846,20 +721,14 @@ public class DBWriter { * Saves a FeedImage object in the database. This method will save all attributes of the FeedImage object. The * contents of FeedComponent-attributes (e.g. the FeedImages's 'feed'-attribute) will not be saved. * - * @param context A context that is used for opening a database connection. * @param image The FeedImage object. */ - public static Future setFeedImage(final Context context, - final FeedImage image) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setImage(image); - adapter.close(); - } + public static Future setFeedImage(final FeedImage image) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setImage(image); + adapter.close(); }); } @@ -867,39 +736,32 @@ public class DBWriter { * Updates download URLs of feeds from a given Map. The key of the Map is the original URL of the feed * and the value is the updated URL */ - public static Future updateFeedDownloadURLs(final Context context, final Map urls) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - for (String key : urls.keySet()) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Replacing URL " + key + " with url " + urls.get(key)); + public static Future updateFeedDownloadURLs(final Map urls) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + for (String key : urls.keySet()) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Replacing URL " + key + " with url " + urls.get(key)); - adapter.setFeedDownloadUrl(key, urls.get(key)); - } - adapter.close(); + adapter.setFeedDownloadUrl(key, urls.get(key)); } + adapter.close(); }); } /** * Saves a FeedPreferences object in the database. The Feed ID of the FeedPreferences-object MUST NOT be 0. * - * @param context Used for opening a database connection. * @param preferences The FeedPreferences object. */ - public static Future setFeedPreferences(final Context context, final FeedPreferences preferences) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedPreferences(preferences); - adapter.close(); - EventDistributor.getInstance().sendFeedUpdateBroadcast(); - } + public static Future setFeedPreferences(final FeedPreferences preferences) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedPreferences(preferences); + adapter.close(); + EventDistributor.getInstance().sendFeedUpdateBroadcast(); }); } @@ -920,17 +782,13 @@ public class DBWriter { public static Future setFeedItemFlattrStatus(final Context context, final FeedItem item, final boolean startFlattrClickWorker) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedItemFlattrStatus(item); - adapter.close(); - if (startFlattrClickWorker) { - new FlattrClickWorker(context).executeAsync(); - } + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedItemFlattrStatus(item); + adapter.close(); + if (startFlattrClickWorker) { + new FlattrClickWorker(context).executeAsync(); } }); } @@ -943,17 +801,13 @@ public class DBWriter { private static Future setFeedFlattrStatus(final Context context, final Feed feed, final boolean startFlattrClickWorker) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedFlattrStatus(feed); - adapter.close(); - if (startFlattrClickWorker) { - new FlattrClickWorker(context).executeAsync(); - } + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedFlattrStatus(feed); + adapter.close(); + if (startFlattrClickWorker) { + new FlattrClickWorker(context).executeAsync(); } }); } @@ -963,18 +817,13 @@ public class DBWriter { * * @param lastUpdateFailed true if last update failed */ - public static Future setFeedLastUpdateFailed(final Context context, - final long feedId, - final boolean lastUpdateFailed) { - return dbExec.submit(new Runnable() { - - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedLastUpdateFailed(feedId, lastUpdateFailed); - adapter.close(); - } + public static Future setFeedLastUpdateFailed(final long feedId, + final boolean lastUpdateFailed) { + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedLastUpdateFailed(feedId, lastUpdateFailed); + adapter.close(); }); } @@ -1002,14 +851,15 @@ public class DBWriter { */ public static Future setFlattredStatus(Context context, FlattrThing thing, boolean startFlattrClickWorker) { // must propagate this to back db - if (thing instanceof FeedItem) + if (thing instanceof FeedItem) { return setFeedItemFlattrStatus(context, (FeedItem) thing, startFlattrClickWorker); - else if (thing instanceof Feed) + } else if (thing instanceof Feed) { return setFeedFlattrStatus(context, (Feed) thing, startFlattrClickWorker); - else if (thing instanceof SimpleFlattrThing) { - } // SimpleFlattrThings are generated on the fly and do not have DB backing - else + } else if (thing instanceof SimpleFlattrThing) { + // SimpleFlattrThings are generated on the fly and do not have DB backing + } else { Log.e(TAG, "flattrQueue processing - thing is neither FeedItem nor Feed nor SimpleFlattrThing"); + } return null; } @@ -1017,16 +867,13 @@ public class DBWriter { /** * Reset flattr status to unflattrd for all items */ - public static Future clearAllFlattrStatus(final Context context) { + public static Future clearAllFlattrStatus() { Log.d(TAG, "clearAllFlattrStatus()"); - return dbExec.submit(new Runnable() { - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.clearAllFlattrStatus(); - adapter.close(); - } + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.clearAllFlattrStatus(); + adapter.close(); }); } @@ -1034,124 +881,95 @@ public class DBWriter { * Set flattr status of the feeds/feeditems in flattrList to flattred at the given timestamp, * where the information has been retrieved from the flattr API */ - public static Future setFlattredStatus(final Context context, final List flattrList) { + public static Future setFlattredStatus(final List flattrList) { Log.d(TAG, "setFlattredStatus to status retrieved from flattr api running with " + flattrList.size() + " items"); // clear flattr status in db - clearAllFlattrStatus(context); + clearAllFlattrStatus(); // submit list with flattred things having normalized URLs to db - return dbExec.submit(new Runnable() { - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - for (Flattr flattr : flattrList) { - adapter.setItemFlattrStatus(formatURIForQuery(flattr.getThing().getUrl()), new FlattrStatus(flattr.getCreated().getTime())); - } - adapter.close(); + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + for (Flattr flattr : flattrList) { + adapter.setItemFlattrStatus(formatURIForQuery(flattr.getThing().getUrl()), new FlattrStatus(flattr.getCreated().getTime())); } + adapter.close(); }); } /** * Sort the FeedItems in the queue with the given Comparator. - * - * @param context A context that is used for opening a database connection. * @param comparator FeedItem comparator * @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to - * false if the caller wants to avoid unexpected updates of the GUI. */ - public static Future sortQueue(final Context context, final Comparator comparator, final boolean broadcastUpdate) { - return dbExec.submit(new Runnable() { - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - final List queue = DBReader.getQueue(context, adapter); + public static Future sortQueue(final Comparator comparator, final boolean broadcastUpdate) { + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + final List queue = DBReader.getQueue(adapter); - if (queue != null) { - Collections.sort(queue, comparator); - adapter.setQueue(queue); - if (broadcastUpdate) { - EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.SORTED)); - } - } else { - Log.e(TAG, "sortQueue: Could not load queue"); + if (queue != null) { + Collections.sort(queue, comparator); + adapter.setQueue(queue); + if (broadcastUpdate) { + EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.SORTED)); } - adapter.close(); + } else { + Log.e(TAG, "sortQueue: Could not load queue"); } + adapter.close(); }); } /** * Sets the 'auto_download'-attribute of specific FeedItem. * - * @param context A context that is used for opening a database connection. * @param feedItem FeedItem. */ - public static Future setFeedItemAutoDownload(final Context context, final FeedItem feedItem, + public static Future setFeedItemAutoDownload(final FeedItem feedItem, final boolean autoDownload) { Log.d(TAG, "FeedItem[id=" + feedItem.getId() + "] SET auto_download " + autoDownload); - return dbExec.submit(new Runnable() { - - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedItemAutoDownload(feedItem, autoDownload); - adapter.close(); - - EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); - } + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedItemAutoDownload(feedItem, autoDownload); + adapter.close(); + EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); }); } /** * Sets the 'auto_download'-attribute of specific FeedItem. - * - * @param context A context that is used for opening a database connection. - * @param feed This feed's episodes will be processed. + * @param feed This feed's episodes will be processed. * @param autoDownload If true, auto download will be enabled for the feed's episodes. Else, - * it will be disabled. */ - public static Future setFeedsItemsAutoDownload(final Context context, final Feed feed, - final boolean autoDownload) { + public static Future setFeedsItemsAutoDownload(final Feed feed, + final boolean autoDownload) { Log.d(TAG, (autoDownload ? "Enabling" : "Disabling") + " auto download for items of feed " + feed.getId()); - return dbExec.submit(new Runnable() { - - @Override - public void run() { - final PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedsItemsAutoDownload(feed, autoDownload); - adapter.close(); - - EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); - } + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedsItemsAutoDownload(feed, autoDownload); + adapter.close(); + EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); }); } /** * Set filter of the feed - * - * @param context Used for opening a database connection. - * @param feedId The feed's ID + * @param feedId The feed's ID * @param filterValues Values that represent properties to filter by */ - public static Future setFeedItemsFilter(final Context context, final long feedId, + public static Future setFeedItemsFilter(final long feedId, final List filterValues) { Log.d(TAG, "setFeedFilter"); - - return dbExec.submit(new Runnable() { - @Override - public void run() { - PodDBAdapter adapter = new PodDBAdapter(context); - adapter.open(); - adapter.setFeedItemFilter(feedId, filterValues); - adapter.close(); - EventBus.getDefault().post(new FeedEvent(FeedEvent.Action.FILTER_CHANGED, feedId)); - } + return dbExec.submit(() -> { + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setFeedItemFilter(feedId, filterValues); + adapter.close(); + EventBus.getDefault().post(new FeedEvent(FeedEvent.Action.FILTER_CHANGED, feedId)); }); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java index 6a8b4a441..91f221f39 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/EpisodeCleanupAlgorithm.java @@ -24,7 +24,7 @@ public interface EpisodeCleanupAlgorithm { * space to free to satisfy the episode cache conditions. If the conditions are already satisfied, this * method should not have any effects. */ - public T getDefaultCleanupParameter(Context context); + public T getDefaultCleanupParameter(); /** * Returns a parameter for performCleanup. @@ -32,5 +32,5 @@ public interface EpisodeCleanupAlgorithm { * @param items A list of FeedItems that are about to be downloaded. The implementation of this interface * should decide how much space to free to satisfy the episode cache conditions. */ - public T getPerformCleanupParameter(Context context, List items); + public T getPerformCleanupParameter(List items); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemStatistics.java b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemStatistics.java index f6a59836b..09949b87e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemStatistics.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemStatistics.java @@ -1,5 +1,7 @@ package de.danoeh.antennapod.core.storage; +import android.database.Cursor; + import java.util.Date; /** @@ -36,6 +38,15 @@ public class FeedItemStatistics { } } + public static FeedItemStatistics fromCursor(Cursor cursor) { + return new FeedItemStatistics( + cursor.getLong(0), + cursor.getInt(1), + cursor.getInt(2), + cursor.getInt(4), + new Date(cursor.getLong(3))); + } + public long getFeedID() { return feedID; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 4714f4880..73037d771 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -17,8 +17,8 @@ import org.apache.commons.lang3.Validate; import java.util.Arrays; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; -import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.event.ProgressEvent; import de.danoeh.antennapod.core.feed.Chapter; @@ -40,6 +40,7 @@ import de.greenrobot.event.EventBus; * Implements methods for accessing the database */ public class PodDBAdapter { + private static final String TAG = "PodDBAdapter"; public static final String DATABASE_NAME = "Antennapod.db"; @@ -53,63 +54,6 @@ public class PodDBAdapter { */ public static final int SEARCH_LIMIT = 30; - // ----------- Column indices - // ----------- General indices - public static final int KEY_ID_INDEX = 0; - public static final int KEY_TITLE_INDEX = 1; - public static final int KEY_FILE_URL_INDEX = 2; - public static final int KEY_DOWNLOAD_URL_INDEX = 3; - public static final int KEY_DOWNLOADED_INDEX = 4; - public static final int KEY_LINK_INDEX = 5; - public static final int KEY_DESCRIPTION_INDEX = 6; - public static final int KEY_PAYMENT_LINK_INDEX = 7; - // ----------- Feed indices - public static final int KEY_LAST_UPDATE_INDEX = 8; - public static final int KEY_LANGUAGE_INDEX = 9; - public static final int KEY_AUTHOR_INDEX = 10; - public static final int KEY_IMAGE_INDEX = 11; - public static final int KEY_TYPE_INDEX = 12; - public static final int KEY_FEED_IDENTIFIER_INDEX = 13; - public static final int KEY_FEED_FLATTR_STATUS_INDEX = 14; - public static final int KEY_FEED_USERNAME_INDEX = 15; - public static final int KEY_FEED_PASSWORD_INDEX = 16; - public static final int KEY_IS_PAGED_INDEX = 17; - public static final int KEY_LOAD_ALL_PAGES_INDEX = 18; - public static final int KEY_NEXT_PAGE_LINK_INDEX = 19; - // ----------- FeedItem indices - public static final int KEY_CONTENT_ENCODED_INDEX = 2; - public static final int KEY_PUBDATE_INDEX = 3; - public static final int KEY_READ_INDEX = 4; - public static final int KEY_MEDIA_INDEX = 8; - public static final int KEY_FEED_INDEX = 9; - public static final int KEY_HAS_SIMPLECHAPTERS_INDEX = 10; - public static final int KEY_ITEM_IDENTIFIER_INDEX = 11; - public static final int KEY_ITEM_FLATTR_STATUS_INDEX = 12; - // ---------- FeedMedia indices - public static final int KEY_DURATION_INDEX = 1; - public static final int KEY_POSITION_INDEX = 5; - public static final int KEY_SIZE_INDEX = 6; - public static final int KEY_MIME_TYPE_INDEX = 7; - public static final int KEY_PLAYBACK_COMPLETION_DATE_INDEX = 8; - public static final int KEY_MEDIA_FEEDITEM_INDEX = 9; - public static final int KEY_PLAYED_DURATION_INDEX = 10; - // --------- Download log indices - public static final int KEY_FEEDFILE_INDEX = 1; - public static final int KEY_FEEDFILETYPE_INDEX = 2; - public static final int KEY_REASON_INDEX = 3; - public static final int KEY_SUCCESSFUL_INDEX = 4; - public static final int KEY_COMPLETION_DATE_INDEX = 5; - public static final int KEY_REASON_DETAILED_INDEX = 6; - public static final int KEY_DOWNLOADSTATUS_TITLE_INDEX = 7; - // --------- Queue indices - public static final int KEY_FEEDITEM_INDEX = 1; - public static final int KEY_QUEUE_FEED_INDEX = 2; - // --------- Chapters indices - public static final int KEY_CHAPTER_START_INDEX = 2; - public static final int KEY_CHAPTER_FEEDITEM_INDEX = 3; - public static final int KEY_CHAPTER_LINK_INDEX = 4; - public static final int KEY_CHAPTER_TYPE_INDEX = 5; - // Key-constants public static final String KEY_ID = "id"; public static final String KEY_TITLE = "title"; @@ -253,12 +197,7 @@ public class PodDBAdapter { public static final String CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM = "CREATE INDEX " + TABLE_NAME_SIMPLECHAPTERS + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_SIMPLECHAPTERS + " (" + KEY_FEEDITEM + ")"; - - - private SQLiteDatabase db; - private final Context context; - private PodDBHelper helper; - + /** * Select all columns from the feed-table */ @@ -287,30 +226,7 @@ public class PodDBAdapter { TABLE_NAME_FEEDS + "." + KEY_LAST_UPDATE_FAILED, TABLE_NAME_FEEDS + "." + KEY_AUTO_DELETE_ACTION, }; - - // column indices for FEED_SEL_STD - public static final int IDX_FEED_SEL_STD_ID = 0; - public static final int IDX_FEED_SEL_STD_TITLE = 1; - public static final int IDX_FEED_SEL_STD_FILE_URL = 2; - public static final int IDX_FEED_SEL_STD_DOWNLOAD_URL = 3; - public static final int IDX_FEED_SEL_STD_DOWNLOADED = 4; - public static final int IDX_FEED_SEL_STD_LINK = 5; - public static final int IDX_FEED_SEL_STD_DESCRIPTION = 6; - public static final int IDX_FEED_SEL_STD_PAYMENT_LINK = 7; - public static final int IDX_FEED_SEL_STD_LASTUPDATE = 8; - public static final int IDX_FEED_SEL_STD_LANGUAGE = 9; - public static final int IDX_FEED_SEL_STD_AUTHOR = 10; - public static final int IDX_FEED_SEL_STD_IMAGE = 11; - public static final int IDX_FEED_SEL_STD_TYPE = 12; - public static final int IDX_FEED_SEL_STD_FEED_IDENTIFIER = 13; - public static final int IDX_FEED_SEL_PREFERENCES_AUTO_DOWNLOAD = 14; - public static final int IDX_FEED_SEL_STD_FLATTR_STATUS = 15; - public static final int IDX_FEED_SEL_STD_IS_PAGED = 16; - public static final int IDX_FEED_SEL_STD_NEXT_PAGE_LINK = 17; - public static final int IDX_FEED_SEL_PREFERENCES_USERNAME = 18; - public static final int IDX_FEED_SEL_PREFERENCES_PASSWORD = 19; - public static final int IDX_FEED_SEL_PREFERENCES_AUTO_DELETE_ACTION = 22; - + /** * Select all columns from the feeditems-table except description and * content-encoded. @@ -321,7 +237,8 @@ public class PodDBAdapter { TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE, TABLE_NAME_FEED_ITEMS + "." + KEY_READ, TABLE_NAME_FEED_ITEMS + "." + KEY_LINK, - TABLE_NAME_FEED_ITEMS + "." + KEY_PAYMENT_LINK, KEY_MEDIA, + TABLE_NAME_FEED_ITEMS + "." + KEY_PAYMENT_LINK, + TABLE_NAME_FEED_ITEMS + "." + KEY_MEDIA, TABLE_NAME_FEED_ITEMS + "." + KEY_FEED, TABLE_NAME_FEED_ITEMS + "." + KEY_HAS_CHAPTERS, TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER, @@ -340,73 +257,59 @@ public class PodDBAdapter { SEL_FI_SMALL_STR = selFiSmall.substring(1, selFiSmall.length() - 1); } - // column indices for FEEDITEM_SEL_FI_SMALL - - public static final int IDX_FI_SMALL_ID = 0; - public static final int IDX_FI_SMALL_TITLE = 1; - public static final int IDX_FI_SMALL_PUBDATE = 2; - public static final int IDX_FI_SMALL_READ = 3; - public static final int IDX_FI_SMALL_LINK = 4; - public static final int IDX_FI_SMALL_PAYMENT_LINK = 5; - public static final int IDX_FI_SMALL_MEDIA = 6; - public static final int IDX_FI_SMALL_FEED = 7; - public static final int IDX_FI_SMALL_HAS_CHAPTERS = 8; - public static final int IDX_FI_SMALL_ITEM_IDENTIFIER = 9; - public static final int IDX_FI_SMALL_FLATTR_STATUS = 10; - public static final int IDX_FI_SMALL_IMAGE = 11; - /** * Select id, description and content-encoded column from feeditems. */ private static final String[] SEL_FI_EXTRA = {KEY_ID, KEY_DESCRIPTION, KEY_CONTENT_ENCODED, KEY_FEED}; - // column indices for SEL_FI_EXTRA - public static final int IDX_FI_EXTRA_ID = 0; - public static final int IDX_FI_EXTRA_DESCRIPTION = 1; - public static final int IDX_FI_EXTRA_CONTENT_ENCODED = 2; - public static final int IDX_FI_EXTRA_FEED = 3; + private SQLiteDatabase db; + private static Context context; + private static PodDBHelper dbHelper; + private static AtomicInteger counter = new AtomicInteger(0); - static PodDBHelper dbHelperSingleton; + public static void init(Context context) { + PodDBAdapter.context = context.getApplicationContext(); + } - private static synchronized PodDBHelper getDbHelperSingleton(Context appContext) { - if (dbHelperSingleton == null) { - dbHelperSingleton = new PodDBHelper(appContext, DATABASE_NAME, null); + public static synchronized PodDBAdapter getInstance() { + if(dbHelper == null) { + dbHelper = new PodDBHelper(PodDBAdapter.context, DATABASE_NAME, null); } - return dbHelperSingleton; + return new PodDBAdapter(); } - public PodDBAdapter(Context c) { - this.context = c; - helper = getDbHelperSingleton(c.getApplicationContext()); - } + private PodDBAdapter() {} public PodDBAdapter open() { + counter.incrementAndGet(); if (db == null || !db.isOpen() || db.isReadOnly()) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Opening DB"); + Log.v(TAG, "Opening DB"); try { - db = helper.getWritableDatabase(); + db = dbHelper.getWritableDatabase(); } catch (SQLException ex) { - ex.printStackTrace(); - db = helper.getReadableDatabase(); + Log.e(TAG, Log.getStackTraceString(ex)); + db = dbHelper.getReadableDatabase(); } } return this; } public void close() { - if (BuildConfig.DEBUG) - Log.d(TAG, "Closing DB"); - //db.close(); + if(counter.decrementAndGet() == 0) { + Log.v(TAG, "Closing DB"); + db.close(); + } + db = null; } - public static boolean deleteDatabase(Context context) { - Log.w(TAG, "Deleting database"); - dbHelperSingleton.close(); - dbHelperSingleton = null; - return context.deleteDatabase(DATABASE_NAME); + public static boolean deleteDatabase() { + if(dbHelper != null) { + dbHelper.close(); + dbHelper = null; + } + return context.deleteDatabase(PodDBAdapter.DATABASE_NAME); } /** @@ -484,7 +387,12 @@ public class PodDBAdapter { * @return the id of the entry */ public long setImage(FeedImage image) { - db.beginTransaction(); + boolean startedTransaction = false; + if(false == db.inTransaction()) { + db.beginTransaction(); + startedTransaction = true; + } + ContentValues values = new ContentValues(); values.put(KEY_TITLE, image.getTitle()); values.put(KEY_DOWNLOAD_URL, image.getDownload_url()); @@ -505,8 +413,10 @@ public class PodDBAdapter { db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(image.getOwner().getId())}); } } - db.setTransactionSuccessful(); - db.endTransaction(); + if(startedTransaction) { + db.setTransactionSuccessful(); + db.endTransaction(); + } return image.getId(); } @@ -527,8 +437,7 @@ public class PodDBAdapter { values.put(KEY_HAS_EMBEDDED_PICTURE, media.hasEmbeddedPicture()); if (media.getPlaybackCompletionDate() != null) { - values.put(KEY_PLAYBACK_COMPLETION_DATE, media - .getPlaybackCompletionDate().getTime()); + values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate().getTime()); } else { values.put(KEY_PLAYBACK_COMPLETION_DATE, 0); } @@ -822,8 +731,7 @@ public class PodDBAdapter { values.put(KEY_LINK, chapter.getLink()); values.put(KEY_CHAPTER_TYPE, chapter.getChapterType()); if (chapter.getId() == 0) { - chapter.setId(db - .insert(TABLE_NAME_SIMPLECHAPTERS, null, values)); + chapter.setId(db.insert(TABLE_NAME_SIMPLECHAPTERS, null, values)); } else { db.update(TABLE_NAME_SIMPLECHAPTERS, values, KEY_ID + "=?", new String[]{String.valueOf(chapter.getId())}); @@ -884,14 +792,6 @@ public class PodDBAdapter { return count; } - public void removeDownloadLogItems(long count) { - if (count > 0) { - final String sql = String.format("DELETE FROM %s WHERE %s in (SELECT %s from %s ORDER BY %s ASC LIMIT %d)", - TABLE_NAME_DOWNLOAD_LOG, KEY_ID, KEY_ID, TABLE_NAME_DOWNLOAD_LOG, KEY_COMPLETION_DATE, count); - db.execSQL(sql, null); - } - } - public void setQueue(List queue) { ContentValues values = new ContentValues(); db.beginTransaction(); @@ -963,11 +863,6 @@ public class PodDBAdapter { db.endTransaction(); } - public void removeDownloadStatus(DownloadStatus remove) { - db.delete(TABLE_NAME_DOWNLOAD_LOG, KEY_ID + "=?", - new String[]{String.valueOf(remove.getId())}); - } - public void clearPlaybackHistory() { ContentValues values = new ContentValues(); values.put(KEY_PLAYBACK_COMPLETION_DATE, 0); @@ -1075,21 +970,14 @@ public class PodDBAdapter { * cursor uses the FEEDITEM_SEL_FI_SMALL selection. */ public final Cursor getQueueCursor() { - Object[] args = (Object[]) new String[]{ - SEL_FI_SMALL_STR + "," + TABLE_NAME_QUEUE + "." + KEY_ID, + Object[] args = new String[] { + SEL_FI_SMALL_STR, TABLE_NAME_FEED_ITEMS, TABLE_NAME_QUEUE, TABLE_NAME_FEED_ITEMS + "." + KEY_ID, TABLE_NAME_QUEUE + "." + KEY_FEEDITEM, - TABLE_NAME_QUEUE + "." + KEY_ID}; - String query = String.format( - "SELECT %s FROM %s INNER JOIN %s ON %s=%s ORDER BY %s", args); + TABLE_NAME_QUEUE + "." + KEY_ID }; + String query = String.format("SELECT %s FROM %s INNER JOIN %s ON %s=%s ORDER BY %s", args); Cursor c = db.rawQuery(query, null); - /* - * Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, - * "INNER JOIN ? ON ?=?", new String[] { TABLE_NAME_QUEUE, - * TABLE_NAME_FEED_ITEMS + "." + KEY_ID, TABLE_NAME_QUEUE + "." + - * KEY_FEEDITEM }, null, null, TABLE_NAME_QUEUE + "." + KEY_FEEDITEM); - */ return c; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java index f6486163c..c2cd273b8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java @@ -148,7 +148,7 @@ public class NetworkUtils { } subscriber.onNext(size); subscriber.onCompleted(); - DBWriter.setFeedMedia(context, media); + DBWriter.setFeedMedia(media); } }) .subscribeOn(Schedulers.newThread()) diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java index 9a1496b75..71d6040ba 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java @@ -83,7 +83,7 @@ public class QueueSorter { } if (comparator != null) { - DBWriter.sortQueue(context, comparator, broadcastUpdate); + DBWriter.sortQueue(comparator, broadcastUpdate); } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java index 3b9e6120c..f37933876 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java @@ -167,7 +167,7 @@ public class FlattrUtils { deleteToken(); FlattrServiceCreator.deleteFlattrService(); showRevokeDialog(context); - DBWriter.clearAllFlattrStatus(context); + DBWriter.clearAllFlattrStatus(); } // ------------------------------------------------ DIALOGS diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/gui/UndoBarController.java b/core/src/main/java/de/danoeh/antennapod/core/util/gui/UndoBarController.java index 26c712af3..5eaff6069 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/gui/UndoBarController.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/gui/UndoBarController.java @@ -89,7 +89,9 @@ public class UndoBarController { public void close() { hideUndoBar(true); - mUndoListener.onHide(mUndoToken); + if(mUndoListener != null) { + mUndoListener.onHide(mUndoToken); + } } public void hideUndoBar(boolean immediate) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java index 752e95985..6e306d30a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java @@ -164,7 +164,7 @@ public interface Playable extends Parcelable, case FeedMedia.PLAYABLE_TYPE_FEEDMEDIA: long mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1); if (mediaId != -1) { - return DBReader.getFeedMedia(context, mediaId); + return DBReader.getFeedMedia(mediaId); } break; case ExternalMedia.PLAYABLE_TYPE_EXTERNAL_MEDIA: diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java index 42aa3b713..efeba888b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java @@ -56,7 +56,7 @@ public abstract class PlaybackController { private final Activity activity; private PlaybackService playbackService; - private Playable media; + protected Playable media; private PlayerStatus status; private ScheduledThreadPoolExecutor schedExecutor; @@ -479,8 +479,10 @@ public abstract class PlaybackController { private void updatePlayButtonAppearance(int resource, CharSequence contentDescription) { ImageButton butPlay = getPlayButton(); - butPlay.setImageResource(resource); - butPlay.setContentDescription(contentDescription); + if(butPlay != null) { + butPlay.setImageResource(resource); + butPlay.setContentDescription(contentDescription); + } } public abstract ImageButton getPlayButton(); -- cgit v1.2.3