diff --git a/CHANGELOG.md b/CHANGELOG.md index 122213dfd..ef72e5a45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,46 +1,62 @@ Change Log ========== +Version 1.6.3 +------------- + +* New features: + * Support for Android Auto + * Sort feeds by number of played episodes + * Statistics modes + * Setting: Enqueue downloaded + * Launch screen +* Improvements + * Chapter duration + * Feed title in deletion confirmation +* Fixes: + * Episodes refresh spinner + * Publication date parsing + * Unknown mime type Version 1.6.2 ------------- * New features: - * Integration of fyyd Podcast Search Engine - * Export subscriptions as HTML - * Rename feeds - * Auto-enable sleep timer - * "has media" filter - * Force gpodder full sync + * Integration of fyyd Podcast Search Engine + * Export subscriptions as HTML + * Rename feeds + * Auto-enable sleep timer + * "has media" filter + * Force gpodder full sync * Improvements: - * Better support for Atom feeds, e.g. summary tag - * Confirmation dialog on mark all as seen - * Number of downloaded episodes in subscription counter - * Gpodder sync error optional - * Search results - * MRSS support - * Sanitize HTML from Atom feed + * Better support for Atom feeds, e.g. summary tag + * Confirmation dialog on mark all as seen + * Number of downloaded episodes in subscription counter + * Gpodder sync error optional + * Search results + * MRSS support + * Sanitize HTML from Atom feed * Fixes: - * Reset sleep timer on shake to current waiting time - * Cast dialog image - * Mini player not showing up - * Audio player cover fragment - * Prevent out of memory and casting crashes + * Reset sleep timer on shake to current waiting time + * Cast dialog image + * Mini player not showing up + * Audio player cover fragment + * Prevent out of memory and casting crashes Version 1.6.0 ------------- * New features: - * Experimental Chromecast support - * Subscription overview - * Proxy support - * Statistics - * Manual gpodder.net sync + * Experimental Chromecast support + * Subscription overview + * Proxy support + * Statistics + * Manual gpodder.net sync * Fixes: - * Audioplayer controls - * Audio ducking - * Video control fade-out - * External media controls - * Feed parsing + * Audioplayer controls + * Audio ducking + * Video control fade-out + * External media controls + * Feed parsing Version 1.5.0 ------------- diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java index 0218b103a..4459fbd08 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java @@ -568,7 +568,9 @@ public class GpodnetService { e.printStackTrace(); throw new GpodnetServiceException(e); } finally { - body.close(); + if (body != null) { + body.close(); + } } return responseString; } 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 c0b17ae25..e620da0bd 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 @@ -387,7 +387,13 @@ public class PlaybackService extends MediaBrowserServiceCompat { List mediaItems = new ArrayList<>(); if (parentId.equals(getResources().getString(R.string.app_name))) { // Root List - mediaItems.add(createBrowsableMediaItemForRoot()); + try { + if (!(taskManager.getQueue().isEmpty())) { + mediaItems.add(createBrowsableMediaItemForRoot()); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } List feeds = DBReader.getFeedList(); for (Feed feed: feeds) { mediaItems.add(createBrowsableMediaItemForFeed(feed)); 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 8ed6718c0..32c642de2 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 @@ -4,7 +4,6 @@ import android.database.Cursor; import android.support.v4.util.ArrayMap; import android.util.Log; -import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -66,23 +65,28 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - List result = getFeedList(adapter); - adapter.close(); - return result; + try { + return getFeedList(adapter); + } finally { + adapter.close(); + } } private static List getFeedList(PodDBAdapter adapter) { - Cursor feedlistCursor = adapter.getAllFeedsCursor(); - List feeds = new ArrayList<>(feedlistCursor.getCount()); - - if (feedlistCursor.moveToFirst()) { - do { - Feed feed = extractFeedFromCursorRow(adapter, feedlistCursor); + Cursor cursor = null; + try { + cursor = adapter.getAllFeedsCursor(); + List feeds = new ArrayList<>(cursor.getCount()); + while (cursor.moveToNext()) { + Feed feed = extractFeedFromCursorRow(adapter, cursor); feeds.add(feed); - } while (feedlistCursor.moveToNext()); + } + return feeds; + } finally { + if (cursor != null) { + cursor.close(); + } } - feedlistCursor.close(); - return feeds; } /** @@ -92,23 +96,26 @@ public final class DBReader { */ public static List getFeedListDownloadUrls() { PodDBAdapter adapter = PodDBAdapter.getInstance(); - List result = new ArrayList<>(); adapter.open(); - Cursor feeds = adapter.getFeedCursorDownloadUrls(); - if (feeds.moveToFirst()) { - do { - result.add(feeds.getString(1)); - } while (feeds.moveToNext()); + Cursor cursor = null; + try { + cursor = adapter.getFeedCursorDownloadUrls(); + List result = new ArrayList<>(cursor.getCount()); + while (cursor.moveToNext()) { + result.add(cursor.getString(1)); + } + return result; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); } - feeds.close(); - adapter.close(); - - return result; } - /** * Loads additional data in to the feed items from other database queries + * * @param items the FeedItems who should have other data loaded */ public static void loadAdditionalFeedItemListData(List items) { @@ -135,20 +142,21 @@ 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 items The FeedItems whose Feed-objects should be loaded. + * @param items The FeedItems whose Feed-objects should be loaded. */ public static void loadFeedDataOfFeedItemList(List items) { List feeds = getFeedList(); + + Map feedIndex = new ArrayMap<>(feeds.size()); + for (Feed feed : feeds) { + feedIndex.put(feed.getId(), feed); + } for (FeedItem item : items) { - for (Feed feed : feeds) { - if (feed.getId() == item.getFeedId()) { - item.setFeed(feed); - break; - } - } - if (item.getFeed() == null) { + Feed feed = feedIndex.get(item.getFeedId()); + if (feed == null) { Log.w(TAG, "No match found for item with ID " + item.getId() + ". Feed ID was " + item.getFeedId()); } + item.setFeed(feed); } } @@ -156,7 +164,7 @@ 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()} instead. * - * @param feed The Feed whose items should be loaded + * @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. */ @@ -165,33 +173,35 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - - Cursor itemlistCursor = adapter.getAllItemsOfFeedCursor(feed); - List items = extractItemlistFromCursor(adapter, - itemlistCursor); - itemlistCursor.close(); - adapter.close(); - - Collections.sort(items, new FeedItemPubdateComparator()); - - for (FeedItem item : items) { - item.setFeed(feed); + Cursor cursor = null; + try { + cursor = adapter.getAllItemsOfFeedCursor(feed); + List items = extractItemlistFromCursor(adapter, cursor); + Collections.sort(items, new FeedItemPubdateComparator()); + for (FeedItem item : items) { + item.setFeed(feed); + } + return items; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); } - - return items; } public static List extractItemlistFromCursor(Cursor itemlistCursor) { Log.d(TAG, "extractItemlistFromCursor() called with: " + "itemlistCursor = [" + itemlistCursor + "]"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - List result = extractItemlistFromCursor(adapter, itemlistCursor); - adapter.close(); - return result; + try { + return extractItemlistFromCursor(adapter, itemlistCursor); + } finally { + adapter.close(); + } } - private static List extractItemlistFromCursor(PodDBAdapter adapter, - Cursor cursor) { + private static List extractItemlistFromCursor(PodDBAdapter adapter, Cursor cursor) { List result = new ArrayList<>(cursor.getCount()); LongList imageIds = new LongList(cursor.getCount()); @@ -206,16 +216,16 @@ public final class DBReader { result.add(item); itemIds.add(item.getId()); } while (cursor.moveToNext()); - Map images = getFeedImages(adapter, imageIds.toArray()); - Map medias = getFeedMedia(adapter, itemIds.toArray()); - for(int i=0; i < result.size(); i++) { + Map images = getFeedImages(adapter, imageIds.toArray()); + Map medias = getFeedMedia(adapter, itemIds); + for (int i = 0; i < result.size(); i++) { FeedItem item = result.get(i); long imageId = imageIds.get(i); FeedImage image = images.get(imageId); item.setImage(image); FeedMedia media = medias.get(item.getId()); item.setMedia(media); - if(media != null) { + if (media != null) { media.setItem(item); } } @@ -223,15 +233,14 @@ public final class DBReader { return result; } - private static Map getFeedMedia(PodDBAdapter adapter, - long... itemIds) { - - String[] ids = new String[itemIds.length]; - for(int i=0, len=itemIds.length; i < len; i++) { - ids[i] = String.valueOf(itemIds[i]); + private static Map getFeedMedia(PodDBAdapter adapter, LongList itemIds) { + List ids = new ArrayList<>(itemIds.size()); + for (long item : itemIds.toArray()) { + ids.add(String.valueOf(item)); } - Map result = new ArrayMap<>(itemIds.length); - Cursor cursor = adapter.getFeedMediaCursor(ids); + + Map result = new ArrayMap<>(itemIds.size()); + Cursor cursor = adapter.getFeedMediaCursor(ids.toArray(new String[0])); try { if (cursor.moveToFirst()) { do { @@ -247,8 +256,7 @@ public final class DBReader { return result; } - private static Feed extractFeedFromCursorRow(PodDBAdapter adapter, - Cursor cursor) { + private static Feed extractFeedFromCursorRow(PodDBAdapter adapter, Cursor cursor) { final FeedImage image; int indexImage = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE); long imageId = cursor.getLong(indexImage); @@ -272,11 +280,17 @@ public final class DBReader { static List getQueue(PodDBAdapter adapter) { Log.d(TAG, "getQueue()"); - Cursor itemlistCursor = adapter.getQueueCursor(); - List items = extractItemlistFromCursor(adapter, itemlistCursor); - itemlistCursor.close(); - loadAdditionalFeedItemListData(items); - return items; + Cursor cursor = null; + try { + cursor = adapter.getQueueCursor(); + List items = extractItemlistFromCursor(adapter, cursor); + loadAdditionalFeedItemListData(items); + return items; + } finally { + if (cursor != null) { + cursor.close(); + } + } } /** @@ -290,22 +304,27 @@ public final class DBReader { Log.d(TAG, "getQueueIDList() called"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - LongList result = getQueueIDList(adapter); - adapter.close(); - return result; + try { + return getQueueIDList(adapter); + } finally { + adapter.close(); + } } - static LongList getQueueIDList(PodDBAdapter adapter) { - Cursor queueCursor = adapter.getQueueIDCursor(); - - LongList queueIds = new LongList(queueCursor.getCount()); - if (queueCursor.moveToFirst()) { - do { - queueIds.add(queueCursor.getLong(0)); - } while (queueCursor.moveToNext()); + private static LongList getQueueIDList(PodDBAdapter adapter) { + Cursor cursor = null; + try { + cursor = adapter.getQueueIDCursor(); + LongList queueIds = new LongList(cursor.getCount()); + while (cursor.moveToNext()) { + queueIds.add(cursor.getLong(0)); + } + return queueIds; + } finally { + if (cursor != null) { + cursor.close(); + } } - queueCursor.close(); - return queueIds; } /** @@ -316,13 +335,15 @@ public final class DBReader { * list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties. */ public static List getQueue() { - Log.d(TAG, "getQueue() called with: " + ""); + Log.d(TAG, "getQueue() called"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - List items = getQueue(adapter); - adapter.close(); - return items; + try { + return getQueue(adapter); + } finally { + adapter.close(); + } } /** @@ -331,22 +352,23 @@ public final class DBReader { * @return A list of FeedItems whose episdoe has been downloaded. */ public static List getDownloadedItems() { - Log.d(TAG, "getDownloadedItems() called with: " + ""); + Log.d(TAG, "getDownloadedItems() called"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - - Cursor itemlistCursor = adapter.getDownloadedItemsCursor(); - List items = extractItemlistFromCursor(adapter, - itemlistCursor); - itemlistCursor.close(); - loadAdditionalFeedItemListData(items); - adapter.close(); - - Collections.sort(items, new FeedItemPubdateComparator()); - - return items; - + Cursor cursor = null; + try { + cursor = adapter.getDownloadedItemsCursor(); + List items = extractItemlistFromCursor(adapter, cursor); + loadAdditionalFeedItemListData(items); + Collections.sort(items, new FeedItemPubdateComparator()); + return items; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); + } } /** @@ -359,20 +381,24 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor itemlistCursor = adapter.getUnreadItemsCursor(); - List items = extractItemlistFromCursor(adapter, itemlistCursor); - itemlistCursor.close(); - - loadAdditionalFeedItemListData(items); - - adapter.close(); - - return items; + Cursor cursor = null; + try { + cursor = adapter.getUnreadItemsCursor(); + List items = extractItemlistFromCursor(adapter, cursor); + loadAdditionalFeedItemListData(items); + return items; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); + } } /** * Loads a list of FeedItems that are considered new. * Excludes items from feeds that do not have keep updated enabled. + * * @return A list of FeedItems that are considered new. */ public static List getNewItemsList() { @@ -380,16 +406,18 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - - Cursor itemlistCursor = adapter.getNewItemsCursor(); - List items = extractItemlistFromCursor(adapter, itemlistCursor); - itemlistCursor.close(); - - loadAdditionalFeedItemListData(items); - - adapter.close(); - - return items; + Cursor cursor = null; + try { + cursor = adapter.getNewItemsCursor(); + List items = extractItemlistFromCursor(adapter, cursor); + loadAdditionalFeedItemListData(items); + return items; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); + } } public static List getFavoriteItemsList() { @@ -397,55 +425,63 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - - Cursor itemlistCursor = adapter.getFavoritesCursor(); - List items = extractItemlistFromCursor(adapter, itemlistCursor); - itemlistCursor.close(); - - loadAdditionalFeedItemListData(items); - - adapter.close(); - - return items; + Cursor cursor = null; + try { + cursor = adapter.getFavoritesCursor(); + List items = extractItemlistFromCursor(adapter, cursor); + loadAdditionalFeedItemListData(items); + return items; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); + } } public static LongList getFavoriteIDList() { Log.d(TAG, "getFavoriteIDList() called"); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor favoritesCursor = adapter.getFavoritesCursor(); - - LongList favoriteIDs = new LongList(favoritesCursor.getCount()); - if (favoritesCursor.moveToFirst()) { - do { - favoriteIDs.add(favoritesCursor.getLong(0)); - } while (favoritesCursor.moveToNext()); + Cursor cursor = null; + try { + cursor = adapter.getFavoritesCursor(); + LongList favoriteIDs = new LongList(cursor.getCount()); + while (cursor.moveToNext()) { + favoriteIDs.add(cursor.getLong(0)); + } + return favoriteIDs; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); } - favoritesCursor.close(); - adapter.close(); - return favoriteIDs; } /** * Loads a list of FeedItems sorted by pubDate in descending order. * - * @param limit The maximum number of episodes that should be loaded. + * @param limit The maximum number of episodes that should be loaded. */ public static List getRecentlyPublishedEpisodes(int limit) { Log.d(TAG, "getRecentlyPublishedEpisodes() called with: " + "limit = [" + limit + "]"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - - Cursor itemlistCursor = adapter.getRecentlyPublishedItemsCursor(limit); - List items = extractItemlistFromCursor(adapter, itemlistCursor); - itemlistCursor.close(); - - loadAdditionalFeedItemListData(items); - - adapter.close(); - - return items; + Cursor cursor = null; + try { + cursor = adapter.getRecentlyPublishedItemsCursor(limit); + List items = extractItemlistFromCursor(adapter, cursor); + loadAdditionalFeedItemListData(items); + return items; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); + } } /** @@ -461,21 +497,29 @@ public final class DBReader { 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++) { - int index = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); - itemIds[i] = Long.toString(mediaCursor.getLong(index)); + Cursor mediaCursor = null; + Cursor itemCursor = null; + try { + mediaCursor = adapter.getCompletedMediaCursor(PLAYBACK_HISTORY_SIZE); + String[] itemIds = new String[mediaCursor.getCount()]; + for (int i = 0; i < itemIds.length && mediaCursor.moveToPosition(i); i++) { + int index = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); + itemIds[i] = Long.toString(mediaCursor.getLong(index)); + } + itemCursor = adapter.getFeedItemCursor(itemIds); + List items = extractItemlistFromCursor(adapter, itemCursor); + loadAdditionalFeedItemListData(items); + Collections.sort(items, new PlaybackCompletionDateComparator()); + return items; + } finally { + if (mediaCursor != null) { + mediaCursor.close(); + } + if (itemCursor != null) { + itemCursor.close(); + } + adapter.close(); } - mediaCursor.close(); - Cursor itemCursor = adapter.getFeedItemCursor(itemIds); - List items = extractItemlistFromCursor(adapter, itemCursor); - loadAdditionalFeedItemListData(items); - itemCursor.close(); - adapter.close(); - - Collections.sort(items, new PlaybackCompletionDateComparator()); - return items; } /** @@ -489,19 +533,21 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor logCursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE); - List downloadLog = new ArrayList<>(logCursor.getCount()); - - if (logCursor.moveToFirst()) { - do { - DownloadStatus status = DownloadStatus.fromCursor(logCursor); - downloadLog.add(status); - } while (logCursor.moveToNext()); + Cursor cursor = null; + try { + cursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE); + List downloadLog = new ArrayList<>(cursor.getCount()); + while (cursor.moveToNext()) { + downloadLog.add(DownloadStatus.fromCursor(cursor)); + } + Collections.sort(downloadLog, new DownloadStatusComparator()); + return downloadLog; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); } - logCursor.close(); - adapter.close(); - Collections.sort(downloadLog, new DownloadStatusComparator()); - return downloadLog; } /** @@ -509,26 +555,28 @@ public final class DBReader { * * @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. + * newest events first. */ public static List getFeedDownloadLog(Feed feed) { Log.d(TAG, "getFeedDownloadLog() called with: " + "feed = [" + feed + "]"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feed.getId()); - List downloadLog = new ArrayList<>(cursor.getCount()); - - if (cursor.moveToFirst()) { - do { - DownloadStatus status = DownloadStatus.fromCursor(cursor); - downloadLog.add(status); - } while (cursor.moveToNext()); + Cursor cursor = null; + try { + cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feed.getId()); + List downloadLog = new ArrayList<>(cursor.getCount()); + while (cursor.moveToNext()) { + downloadLog.add(DownloadStatus.fromCursor(cursor)); + } + Collections.sort(downloadLog, new DownloadStatusComparator()); + return downloadLog; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); } - cursor.close(); - adapter.close(); - Collections.sort(downloadLog, new DownloadStatusComparator()); - return downloadLog; } /** @@ -542,103 +590,91 @@ public final class DBReader { Log.d(TAG, "getFeedStatisticsList() called"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - List result = new ArrayList<>(); - Cursor cursor = adapter.getFeedStatisticsCursor(); - if (cursor.moveToFirst()) { - do { + Cursor cursor = null; + try { + cursor = adapter.getFeedStatisticsCursor(); + List result = new ArrayList<>(cursor.getCount()); + while (cursor.moveToNext()) { FeedItemStatistics fis = FeedItemStatistics.fromCursor(cursor); result.add(fis); - } while (cursor.moveToNext()); + } + return result; + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); } - - cursor.close(); - adapter.close(); - return result; } /** * Loads a specific Feed from the database. * - * @param feedId The ID of the Feed + * @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 long feedId) { Log.d(TAG, "getFeed() called with: " + "feedId = [" + feedId + "]"); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Feed result = getFeed(feedId, adapter); - adapter.close(); - return result; + try { + return getFeed(feedId, adapter); + } finally { + adapter.close(); + } } static Feed getFeed(final long feedId, PodDBAdapter adapter) { Feed feed = null; - - Cursor feedCursor = adapter.getFeedCursor(feedId); - if (feedCursor.moveToFirst()) { - feed = extractFeedFromCursorRow(adapter, feedCursor); - feed.setItems(getFeedItemList(feed)); - } else { - Log.e(TAG, "getFeed could not find feed with id " + feedId); - } - feedCursor.close(); - return feed; - } - - 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)); - if (!itemCursor.moveToFirst()) { - itemCursor.close(); - return null; - } - List list = extractItemlistFromCursor(adapter, itemCursor); - itemCursor.close(); - if (list.size() > 0) { - item = list.get(0); - loadAdditionalFeedItemListData(list); - if (item.hasChapters()) { - loadChaptersOfFeedItem(adapter, item); + Cursor cursor = null; + try { + cursor = adapter.getFeedCursor(feedId); + if (cursor.moveToNext()) { + feed = extractFeedFromCursorRow(adapter, cursor); + feed.setItems(getFeedItemList(feed)); + } else { + Log.e(TAG, "getFeed could not find feed with id " + feedId); + } + return feed; + } finally { + if (cursor != null) { + cursor.close(); } } - return item; } - static List getFeedItems(PodDBAdapter adapter, final long... itemIds) { + private static FeedItem getFeedItem(final long itemId, PodDBAdapter adapter) { + Log.d(TAG, "Loading feeditem with id " + itemId); - String[] ids = new String[itemIds.length]; - for(int i = 0; i < itemIds.length; i++) { - long itemId = itemIds[i]; - ids[i] = Long.toString(itemId); - } - - List result; - - Cursor itemCursor = adapter.getFeedItemCursor(ids); - if (itemCursor.moveToFirst()) { - result = extractItemlistFromCursor(adapter, itemCursor); - loadAdditionalFeedItemListData(result); - for(FeedItem item : result) { - if (item.hasChapters()) { - loadChaptersOfFeedItem(adapter, item); + FeedItem item = null; + Cursor cursor = null; + try { + cursor = adapter.getFeedItemCursor(Long.toString(itemId)); + if (cursor.moveToNext()) { + List list = extractItemlistFromCursor(adapter, cursor); + if (!list.isEmpty()) { + item = list.get(0); + loadAdditionalFeedItemListData(list); + if (item.hasChapters()) { + loadChaptersOfFeedItem(adapter, item); + } } } - } else { - result = Collections.emptyList(); + return item; + } finally { + if (cursor != null) { + cursor.close(); + } } - itemCursor.close(); - return result; - } /** * 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 itemId The ID of the FeedItem + * @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. */ @@ -647,51 +683,42 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - FeedItem item = getFeedItem(itemId, adapter); - adapter.close(); - return item; + try { + return getFeedItem(itemId, adapter); + } finally { + adapter.close(); + } } 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); - if (itemCursor.moveToFirst()) { - List list = extractItemlistFromCursor(adapter, itemCursor); - if (list.size() > 0) { + Cursor cursor = null; + try { + cursor = adapter.getFeedItemCursor(podcastUrl, episodeUrl); + if (!cursor.moveToNext()) { + return null; + } + List list = extractItemlistFromCursor(adapter, cursor); + FeedItem item = null; + if (!list.isEmpty()) { item = list.get(0); loadAdditionalFeedItemListData(list); if (item.hasChapters()) { loadChaptersOfFeedItem(adapter, item); } } + return item; + } finally { + if (cursor != null) { + cursor.close(); + } } - itemCursor.close(); - return item; } - /** - * Loads specific FeedItems from the database. This method canbe used for loading more - * than one FeedItem - * - * @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 long... itemIds) { - Log.d(TAG, "getFeedItems() called with: " + "itemIds = [" + Arrays.toString(itemIds) + "]"); - PodDBAdapter adapter = PodDBAdapter.getInstance(); - adapter.open(); - List items = getFeedItems(adapter, itemIds); - adapter.close(); - return items; - } - - /** * Returns credentials based on image URL * - * @param imageUrl The URL of the image + * @param imageUrl The URL of the image * @return Credentials in format ":", empty String if no authorization given */ public static String getImageAuthentication(final String imageUrl) { @@ -699,20 +726,22 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - String credentials = getImageAuthentication(imageUrl, adapter); - adapter.close(); - return credentials; - + try { + return getImageAuthentication(imageUrl, adapter); + } finally { + adapter.close(); + } } - static String getImageAuthentication(final String imageUrl, PodDBAdapter adapter) { + private static String getImageAuthentication(final String imageUrl, PodDBAdapter adapter) { String credentials = null; - Cursor cursor = adapter.getImageAuthenticationCursor(imageUrl); + Cursor cursor = null; try { + cursor = adapter.getImageAuthenticationCursor(imageUrl); if (cursor.moveToFirst()) { String username = cursor.getString(0); String password = cursor.getString(1); - if(username != null && password != null) { + if (username != null && password != null) { credentials = username + ":" + password; } else { credentials = ""; @@ -721,7 +750,9 @@ public final class DBReader { credentials = ""; } } finally { - cursor.close(); + if (cursor != null) { + cursor.close(); + } } return credentials; } @@ -739,31 +770,39 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - FeedItem item = getFeedItem(podcastUrl, episodeUrl, adapter); - adapter.close(); - return item; + try { + return getFeedItem(podcastUrl, episodeUrl, adapter); + } finally { + adapter.close(); + } } /** * Loads additional information about a FeedItem, e.g. shownotes * - * @param item The FeedItem + * @param item The FeedItem */ public static void loadExtraInformationOfFeedItem(final FeedItem item) { Log.d(TAG, "loadExtraInformationOfFeedItem() called with: " + "item = [" + item + "]"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor extraCursor = adapter.getExtraInformationOfItem(item); - if (extraCursor.moveToFirst()) { - 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); + Cursor cursor = null; + try { + cursor = adapter.getExtraInformationOfItem(item); + if (cursor.moveToFirst()) { + int indexDescription = cursor.getColumnIndex(PodDBAdapter.KEY_DESCRIPTION); + String description = cursor.getString(indexDescription); + int indexContentEncoded = cursor.getColumnIndex(PodDBAdapter.KEY_CONTENT_ENCODED); + String contentEncoded = cursor.getString(indexContentEncoded); + item.setDescription(description); + item.setContentEncoded(contentEncoded); + } + } finally { + if (cursor != null) { + cursor.close(); + } + adapter.close(); } - extraCursor.close(); - adapter.close(); } /** @@ -771,56 +810,64 @@ 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 item The FeedItem + * @param item The FeedItem */ public static void loadChaptersOfFeedItem(final FeedItem item) { Log.d(TAG, "loadChaptersOfFeedItem() called with: " + "item = [" + item + "]"); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - loadChaptersOfFeedItem(adapter, item); - adapter.close(); + try { + loadChaptersOfFeedItem(adapter, item); + } finally { + adapter.close(); + } } static void loadChaptersOfFeedItem(PodDBAdapter adapter, FeedItem item) { - Cursor chapterCursor = adapter.getSimpleChaptersOfFeedItemCursor(item); - if (chapterCursor.moveToFirst()) { - item.setChapters(new ArrayList<>()); - do { - 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); + Cursor cursor = null; + try { + cursor = adapter.getSimpleChaptersOfFeedItemCursor(item); + int chaptersCount = cursor.getCount(); + if (chaptersCount == 0) { + item.setChapters(null); + return; + } + item.setChapters(new ArrayList<>(chaptersCount)); + while (cursor.moveToNext()) { + int indexType = cursor.getColumnIndex(PodDBAdapter.KEY_CHAPTER_TYPE); + int indexStart = cursor.getColumnIndex(PodDBAdapter.KEY_START); + int indexTitle = cursor.getColumnIndex(PodDBAdapter.KEY_TITLE); + int indexLink = cursor.getColumnIndex(PodDBAdapter.KEY_LINK); - int chapterType = chapterCursor.getInt(indexType); + int chapterType = cursor.getInt(indexType); Chapter chapter = null; - long start = chapterCursor.getLong(indexStart); - String title = chapterCursor.getString(indexTitle); - String link = chapterCursor.getString(indexLink); + long start = cursor.getLong(indexStart); + String title = cursor.getString(indexTitle); + String link = cursor.getString(indexLink); switch (chapterType) { case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: - chapter = new SimpleChapter(start, title, item, - link); + chapter = new SimpleChapter(start, title, item, link); break; case ID3Chapter.CHAPTERTYPE_ID3CHAPTER: - chapter = new ID3Chapter(start, title, item, - link); + chapter = new ID3Chapter(start, title, item, link); break; case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: - chapter = new VorbisCommentChapter(start, - title, item, link); + chapter = new VorbisCommentChapter(start, title, item, link); break; } if (chapter != null) { - int indexId = chapterCursor.getColumnIndex(PodDBAdapter.KEY_ID); - chapter.setId(chapterCursor.getLong(indexId)); + int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); + chapter.setId(cursor.getLong(indexId)); item.getChapters().add(chapter); } - } while (chapterCursor.moveToNext()); - } else { - item.setChapters(null); + } + } finally { + if (cursor != null) { + cursor.close(); + } } - chapterCursor.close(); } /** @@ -828,13 +875,17 @@ public final class DBReader { * * @return The number of downloaded episodes. */ + public static int getNumberOfDownloadedEpisodes() { Log.d(TAG, "getNumberOfDownloadedEpisodes() called with: " + ""); + PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - final int result = adapter.getNumberOfDownloadedEpisodes(); - adapter.close(); - return result; + try { + return adapter.getNumberOfDownloadedEpisodes(); + } finally { + adapter.close(); + } } /** @@ -847,9 +898,11 @@ public final class DBReader { Log.d(TAG, "getFeedImage() called with: " + "imageId = [" + imageId + "]"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - FeedImage result = getFeedImage(adapter, imageId); - adapter.close(); - return result; + try { + return getFeedImage(adapter, imageId); + } finally { + adapter.close(); + } } /** @@ -868,21 +921,22 @@ public final class DBReader { * @param imageIds The ids of the images * @return Map that associates the id of an image with the image itself */ - private static Map getFeedImages(PodDBAdapter adapter, final long... imageIds) { + private static Map getFeedImages(PodDBAdapter adapter, final long... imageIds) { String[] ids = new String[imageIds.length]; - for(int i=0, len=imageIds.length; i < len; i++) { + for (int i = 0, len = imageIds.length; i < len; i++) { ids[i] = String.valueOf(imageIds[i]); } Cursor cursor = adapter.getImageCursor(ids); - Map result = new ArrayMap<>(cursor.getCount()); + int imageCount = cursor.getCount(); + if (imageCount == 0) { + return Collections.emptyMap(); + } + Map result = new ArrayMap<>(imageCount); try { - if ((cursor.getCount() == 0) || !cursor.moveToFirst()) { - return Collections.emptyMap(); - } - do { + while (cursor.moveToNext()) { FeedImage image = FeedImage.fromCursor(cursor); result.put(image.getId(), image); - } while(cursor.moveToNext()); + } } finally { cursor.close(); } @@ -899,29 +953,31 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor mediaCursor = adapter.getSingleFeedMediaCursor(mediaId); - - if (!mediaCursor.moveToFirst()) { - mediaCursor.close(); - return null; - } - - int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); - long itemId = mediaCursor.getLong(indexFeedItem); - FeedMedia media = FeedMedia.fromCursor(mediaCursor); - mediaCursor.close(); - - if(media != null) { - FeedItem item = getFeedItem(itemId); - if (item != null) { - media.setItem(item); - item.setMedia(media); + Cursor mediaCursor = null; + try { + mediaCursor = adapter.getSingleFeedMediaCursor(mediaId); + if (!mediaCursor.moveToFirst()) { + return null; } + + int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM); + long itemId = mediaCursor.getLong(indexFeedItem); + FeedMedia media = FeedMedia.fromCursor(mediaCursor); + if (media != null) { + FeedItem item = getFeedItem(itemId); + if (item != null) { + media.setItem(item); + item.setMedia(media); + } + } + return media; + + } finally { + if (mediaCursor != null) { + mediaCursor.close(); + } + adapter.close(); } - - adapter.close(); - - return media; } /** @@ -1100,7 +1156,6 @@ public final class DBReader { * 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. - * */ public static NavDrawerData getNavDrawerData() { Log.d(TAG, "getNavDrawerData() called with: " + ""); @@ -1108,48 +1163,48 @@ public final class DBReader { adapter.open(); List feeds = getFeedList(adapter); long[] feedIds = new long[feeds.size()]; - for(int i=0; i < feeds.size(); i++) { + for (int i = 0; i < feeds.size(); i++) { feedIds[i] = feeds.get(i).getId(); } final LongIntMap feedCounters = adapter.getFeedCounters(feedIds); Comparator comparator; int feedOrder = UserPreferences.getFeedOrder(); - if(feedOrder == UserPreferences.FEED_ORDER_COUNTER) { + if (feedOrder == UserPreferences.FEED_ORDER_COUNTER) { comparator = (lhs, rhs) -> { long counterLhs = feedCounters.get(lhs.getId()); long counterRhs = feedCounters.get(rhs.getId()); - if(counterLhs > counterRhs) { + if (counterLhs > counterRhs) { // reverse natural order: podcast with most unplayed episodes first return -1; - } else if(counterLhs == counterRhs) { + } else if (counterLhs == counterRhs) { return lhs.getTitle().compareToIgnoreCase(rhs.getTitle()); } else { return 1; } }; - } else if(feedOrder == UserPreferences.FEED_ORDER_ALPHABETICAL) { + } else if (feedOrder == UserPreferences.FEED_ORDER_ALPHABETICAL) { comparator = (lhs, rhs) -> { String t1 = lhs.getTitle(); String t2 = rhs.getTitle(); - if(t1 == null) { + if (t1 == null) { return 1; - } else if(t2 == null) { + } else if (t2 == null) { return -1; } else { return t1.compareToIgnoreCase(t2); } }; - } else if(feedOrder == UserPreferences.FEED_ORDER_MOST_PLAYED) { + } else if (feedOrder == UserPreferences.FEED_ORDER_MOST_PLAYED) { final LongIntMap playedCounters = adapter.getPlayedEpisodesCounters(feedIds); comparator = (lhs, rhs) -> { long counterLhs = playedCounters.get(lhs.getId()); long counterRhs = playedCounters.get(rhs.getId()); - if(counterLhs > counterRhs) { + if (counterLhs > counterRhs) { // podcast with most played episodes first return -1; - } else if(counterLhs == counterRhs) { + } else if (counterLhs == counterRhs) { return lhs.getTitle().compareToIgnoreCase(rhs.getTitle()); } else { return 1; @@ -1157,17 +1212,17 @@ public final class DBReader { }; } else { comparator = (lhs, rhs) -> { - if(lhs.getItems() == null || lhs.getItems().size() == 0) { + if (lhs.getItems() == null || lhs.getItems().size() == 0) { List items = DBReader.getFeedItemList(lhs); lhs.setItems(items); } - if(rhs.getItems() == null || rhs.getItems().size() == 0) { + if (rhs.getItems() == null || rhs.getItems().size() == 0) { List items = DBReader.getFeedItemList(rhs); rhs.setItems(items); } - if(lhs.getMostRecentItem() == null) { + if (lhs.getMostRecentItem() == null) { return 1; - } else if(rhs.getMostRecentItem() == null) { + } else if (rhs.getMostRecentItem() == null) { return -1; } else { Date d1 = lhs.getMostRecentItem().getPubDate(); 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 2d0b5c56a..bde63884a 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 @@ -1156,7 +1156,9 @@ public class PodDBAdapter { + TABLE_NAME_FEED_IMAGES + " WHERE " + KEY_ID + " IN " + buildInOperator(neededLength), parts); } - return new MergeCursor(cursors); + Cursor result = new MergeCursor(cursors); + result.moveToFirst(); + return result; } else { return db.query(TABLE_NAME_FEED_IMAGES, null, KEY_ID + " IN " + buildInOperator(length), imageIds, null, null, null); @@ -1341,7 +1343,9 @@ public class PodDBAdapter { + TABLE_NAME_FEED_MEDIA + " WHERE " + KEY_FEEDITEM + " IN " + buildInOperator(neededLength), parts); } - return new MergeCursor(cursors); + Cursor result = new MergeCursor(cursors); + result.moveToFirst(); + return result; } else { return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_FEEDITEM + " IN " + buildInOperator(length), itemIds, null, null, null);