summaryrefslogtreecommitdiff
path: root/src/de/danoeh/antennapod/storage
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/danoeh/antennapod/storage')
-rw-r--r--src/de/danoeh/antennapod/storage/DBReader.java908
-rw-r--r--src/de/danoeh/antennapod/storage/DBTasks.java895
-rw-r--r--src/de/danoeh/antennapod/storage/DBWriter.java974
-rw-r--r--src/de/danoeh/antennapod/storage/DownloadRequestException.java25
-rw-r--r--src/de/danoeh/antennapod/storage/DownloadRequester.java367
-rw-r--r--src/de/danoeh/antennapod/storage/FeedItemStatistics.java70
-rw-r--r--src/de/danoeh/antennapod/storage/FeedSearcher.java57
-rw-r--r--src/de/danoeh/antennapod/storage/PodDBAdapter.java1391
8 files changed, 0 insertions, 4687 deletions
diff --git a/src/de/danoeh/antennapod/storage/DBReader.java b/src/de/danoeh/antennapod/storage/DBReader.java
deleted file mode 100644
index e49ea4f83..000000000
--- a/src/de/danoeh/antennapod/storage/DBReader.java
+++ /dev/null
@@ -1,908 +0,0 @@
-package de.danoeh.antennapod.storage;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.feed.*;
-import de.danoeh.antennapod.service.download.DownloadStatus;
-import de.danoeh.antennapod.util.DownloadError;
-import de.danoeh.antennapod.util.comparator.DownloadStatusComparator;
-import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator;
-import de.danoeh.antennapod.util.comparator.PlaybackCompletionDateComparator;
-import de.danoeh.antennapod.util.flattr.FlattrStatus;
-import de.danoeh.antennapod.util.flattr.FlattrThing;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Provides methods for reading data from the AntennaPod database.
- * In general, all database calls in DBReader-methods are executed on the caller's thread.
- * This means that the caller should make sure that DBReader-methods are not executed on the GUI-thread.
- * This class will use the {@link de.danoeh.antennapod.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)}.
- */
- public static final int PLAYBACK_HISTORY_SIZE = 50;
-
- /**
- * Maximum size of the list returned by {@link #getDownloadLog(android.content.Context)}.
- */
- public static final int DOWNLOAD_LOG_SIZE = 200;
-
-
- private 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.feed.Feed)}.
- */
- public static List<Feed> getFeedList(final Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting Feedlist");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<Feed> result = getFeedList(adapter);
- adapter.close();
- return result;
- }
-
- private static List<Feed> getFeedList(PodDBAdapter adapter) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting Feedlist");
-
- Cursor feedlistCursor = adapter.getAllFeedsCursor();
- List<Feed> feeds = new ArrayList<Feed>(feedlistCursor.getCount());
-
- if (feedlistCursor.moveToFirst()) {
- do {
- Feed feed = extractFeedFromCursorRow(adapter, feedlistCursor);
- feeds.add(feed);
- } while (feedlistCursor.moveToNext());
- }
- feedlistCursor.close();
- return feeds;
- }
-
- /**
- * 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<String> getFeedListDownloadUrls(final Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- List<String> result = new ArrayList<String>();
- adapter.open();
- Cursor feeds = adapter.getFeedCursorDownloadUrls();
- if (feeds.moveToFirst()) {
- do {
- result.add(feeds.getString(1));
- } while (feeds.moveToNext());
- }
- feeds.close();
- adapter.close();
-
- return result;
- }
-
- /**
- * Returns a list of 'expired Feeds', i.e. Feeds that have not been updated for a certain amount of time.
- *
- * @param context A context that is used for opening a database connection.
- * @param expirationTime Time that is used for determining whether a feed is outdated or not.
- * A Feed is considered expired if 'lastUpdate < (currentTime - expirationTime)' evaluates to true.
- * @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.feed.Feed)}.
- */
- public static List<Feed> getExpiredFeedsList(final Context context, final long expirationTime) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, String.format("getExpiredFeedsList(%d)", expirationTime));
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor feedlistCursor = adapter.getExpiredFeedsCursor(expirationTime);
- List<Feed> feeds = new ArrayList<Feed>(feedlistCursor.getCount());
-
- if (feedlistCursor.moveToFirst()) {
- do {
- Feed feed = extractFeedFromCursorRow(adapter, feedlistCursor);
- feeds.add(feed);
- } while (feedlistCursor.moveToNext());
- }
- feedlistCursor.close();
- return feeds;
- }
-
- /**
- * Takes a list of FeedItems and loads their corresponding Feed-objects from the database.
- * 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<FeedItem> items) {
- List<Feed> feeds = getFeedList(context);
- for (FeedItem item : items) {
- for (Feed feed : feeds) {
- if (feed.getId() == item.getFeedId()) {
- item.setFeed(feed);
- break;
- }
- }
- if (item.getFeed() == null) {
- Log.w(TAG, "No match found for item with ID " + item.getId() + ". Feed ID was " + item.getFeedId());
- }
- }
- }
-
- /**
- * 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.
- *
- * @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<FeedItem> getFeedItemList(Context context,
- final Feed feed) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting Feeditems of feed " + feed.getTitle());
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor itemlistCursor = adapter.getAllItemsOfFeedCursor(feed);
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
-
- Collections.sort(items, new FeedItemPubdateComparator());
-
- adapter.close();
-
- for (FeedItem item : items) {
- item.setFeed(feed);
- }
-
- return items;
- }
-
- static List<FeedItem> extractItemlistFromCursor(Context context, Cursor itemlistCursor) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<FeedItem> result = extractItemlistFromCursor(adapter, itemlistCursor);
- adapter.close();
- return result;
- }
-
- private static List<FeedItem> extractItemlistFromCursor(
- PodDBAdapter adapter, Cursor itemlistCursor) {
- ArrayList<String> itemIds = new ArrayList<String>();
- List<FeedItem> items = new ArrayList<FeedItem>(
- itemlistCursor.getCount());
-
- if (itemlistCursor.moveToFirst()) {
- do {
- FeedItem item = new FeedItem();
-
- item.setId(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID));
- item.setTitle(itemlistCursor
- .getString(PodDBAdapter.IDX_FI_SMALL_TITLE));
- item.setLink(itemlistCursor
- .getString(PodDBAdapter.IDX_FI_SMALL_LINK));
- item.setPubDate(new Date(itemlistCursor
- .getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE)));
- item.setPaymentLink(itemlistCursor
- .getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK));
- item.setFeedId(itemlistCursor
- .getLong(PodDBAdapter.IDX_FI_SMALL_FEED));
- itemIds.add(String.valueOf(item.getId()));
-
- item.setRead((itemlistCursor
- .getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0));
- item.setItemIdentifier(itemlistCursor
- .getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER));
- item.setFlattrStatus(new FlattrStatus(itemlistCursor
- .getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS)));
-
- long imageIndex = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_IMAGE);
- if (imageIndex != 0) {
- item.setImage(getFeedImage(adapter, imageIndex));
- }
-
- // extract chapters
- boolean hasSimpleChapters = itemlistCursor
- .getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0;
- if (hasSimpleChapters) {
- Cursor chapterCursor = adapter
- .getSimpleChaptersOfFeedItemCursor(item);
- if (chapterCursor.moveToFirst()) {
- item.setChapters(new ArrayList<Chapter>());
- do {
- int chapterType = chapterCursor
- .getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX);
- 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);
-
- 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;
- }
- if (chapter != null) {
- chapter.setId(chapterCursor
- .getLong(PodDBAdapter.KEY_ID_INDEX));
- item.getChapters().add(chapter);
- }
- } while (chapterCursor.moveToNext());
- }
- chapterCursor.close();
- }
- items.add(item);
- } while (itemlistCursor.moveToNext());
- }
-
- extractMediafromItemlist(adapter, items, itemIds);
- return items;
- }
-
- private static void extractMediafromItemlist(PodDBAdapter adapter,
- List<FeedItem> items, ArrayList<String> itemIds) {
-
- List<FeedItem> itemsCopy = new ArrayList<FeedItem>(items);
- Cursor cursor = adapter.getFeedMediaCursorByItemID(itemIds
- .toArray(new String[itemIds.size()]));
- if (cursor.moveToFirst()) {
- do {
- long itemId = cursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX);
- // find matching feed item
- FeedItem item = getMatchingItemForMedia(itemId, itemsCopy);
- if (item != null) {
- item.setMedia(extractFeedMediaFromCursorRow(cursor));
- item.getMedia().setItem(item);
- }
- } while (cursor.moveToNext());
- 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);
- }
-
- 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));
- }
-
- 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);
- } 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)));
-
- if (image != null) {
- 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,
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_USERNAME),
- cursor.getString(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_PASSWORD));
-
- feed.setPreferences(preferences);
- return feed;
- }
-
- private static FeedItem getMatchingItemForMedia(long itemId,
- List<FeedItem> items) {
- for (FeedItem item : items) {
- if (item.getId() == itemId) {
- return item;
- }
- }
- return null;
- }
-
- static List<FeedItem> getQueue(Context context, PodDBAdapter adapter) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting queue");
-
- Cursor itemlistCursor = adapter.getQueueCursor();
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
- loadFeedDataOfFeedItemlist(context, 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.
- *
- * @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.util.QueueAccess} object for easier access to the queue's properties.
- */
- public static List<Long> getQueueIDList(Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
-
- adapter.open();
- List<Long> result = getQueueIDList(adapter);
- adapter.close();
-
- return result;
- }
-
- static List<Long> getQueueIDList(PodDBAdapter adapter) {
- adapter.open();
- Cursor queueCursor = adapter.getQueueIDCursor();
-
- List<Long> queueIds = new ArrayList<Long>(queueCursor.getCount());
- if (queueCursor.moveToFirst()) {
- do {
- queueIds.add(queueCursor.getLong(0));
- } while (queueCursor.moveToNext());
- }
- return queueIds;
- }
-
-
- /**
- * 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.
- *
- * @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.util.QueueAccess} object for easier access to the queue's properties.
- */
- public static List<FeedItem> getQueue(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting queue");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<FeedItem> items = getQueue(context, adapter);
- adapter.close();
- return items;
- }
-
- /**
- * 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<FeedItem> getDownloadedItems(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting downloaded items");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor itemlistCursor = adapter.getDownloadedItemsCursor();
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
- loadFeedDataOfFeedItemlist(context, items);
- Collections.sort(items, new FeedItemPubdateComparator());
-
- adapter.close();
- return items;
-
- }
-
- /**
- * 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. If the FeedItems in the list are not used,
- * consider using {@link #getUnreadItemIds(android.content.Context)} instead.
- */
- public static List<FeedItem> getUnreadItemsList(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting unread items list");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor itemlistCursor = adapter.getUnreadItemsCursor();
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
-
- loadFeedDataOfFeedItemlist(context, 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 long[] getUnreadItemIds(Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor cursor = adapter.getUnreadItemIdsCursor();
- long[] itemIds = new long[cursor.getCount()];
- int i = 0;
- if (cursor.moveToFirst()) {
- do {
- itemIds[i] = cursor.getLong(PodDBAdapter.KEY_ID_INDEX);
- i++;
- } while (cursor.moveToNext());
- }
- 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<FeedItem> getRecentlyPublishedEpisodes(Context context, int limit) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting recently published items list");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- Cursor itemlistCursor = adapter.getRecentlyPublishedItemsCursor(limit);
- List<FeedItem> items = extractItemlistFromCursor(adapter,
- itemlistCursor);
- itemlistCursor.close();
-
- loadFeedDataOfFeedItemlist(context, items);
-
- adapter.close();
-
- return items;
- }
-
- /**
- * 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<FeedItem> getPlaybackHistory(final Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading playback history");
- final int PLAYBACK_HISTORY_SIZE = 50;
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- 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));
- }
- mediaCursor.close();
- Cursor itemCursor = adapter.getFeedItemCursor(itemIds);
- List<FeedItem> items = extractItemlistFromCursor(adapter, itemCursor);
- loadFeedDataOfFeedItemlist(context, items);
- itemCursor.close();
- adapter.close();
-
- Collections.sort(items, new PlaybackCompletionDateComparator());
- return items;
- }
-
- /**
- * 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<DownloadStatus> getDownloadLog(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Extracting DownloadLog");
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor logCursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE);
- List<DownloadStatus> downloadLog = new ArrayList<DownloadStatus>(
- logCursor.getCount());
-
- if (logCursor.moveToFirst()) {
- do {
- long id = logCursor.getLong(PodDBAdapter.KEY_ID_INDEX);
-
- long feedfileId = logCursor
- .getLong(PodDBAdapter.KEY_FEEDFILE_INDEX);
- int feedfileType = logCursor
- .getInt(PodDBAdapter.KEY_FEEDFILETYPE_INDEX);
- boolean successful = logCursor
- .getInt(PodDBAdapter.KEY_SUCCESSFUL_INDEX) > 0;
- int reason = logCursor.getInt(PodDBAdapter.KEY_REASON_INDEX);
- String reasonDetailed = logCursor
- .getString(PodDBAdapter.KEY_REASON_DETAILED_INDEX);
- String title = logCursor
- .getString(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE_INDEX);
- Date completionDate = new Date(
- logCursor
- .getLong(PodDBAdapter.KEY_COMPLETION_DATE_INDEX)
- );
- downloadLog.add(new DownloadStatus(id, title, feedfileId,
- feedfileType, successful, DownloadError.fromCode(reason), completionDate,
- reasonDetailed));
-
- } while (logCursor.moveToNext());
- }
- logCursor.close();
- Collections.sort(downloadLog, new DownloadStatusComparator());
- return downloadLog;
- }
-
- /**
- * Loads the FeedItemStatistics objects of all Feeds in the database. This method should be preferred over
- * {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.feed.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<FeedItemStatistics> getFeedStatisticsList(final Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<FeedItemStatistics> result = new ArrayList<FeedItemStatistics>();
- 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))));
- } while (cursor.moveToNext());
- }
-
- cursor.close();
- adapter.close();
- return result;
- }
-
- /**
- * 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);
- adapter.open();
- Feed result = getFeed(context, 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);
- Feed feed = null;
-
- Cursor feedCursor = adapter.getFeedCursor(feedId);
- if (feedCursor.moveToFirst()) {
- feed = extractFeedFromCursorRow(adapter, feedCursor);
- feed.setItems(getFeedItemList(context, feed));
- } else {
- Log.e(TAG, "getFeed could not find feed with id " + feedId);
- }
- feedCursor.close();
- return feed;
- }
-
- static FeedItem getFeedItem(final Context context, final long itemId, PodDBAdapter adapter) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading feeditem with id " + itemId);
- FeedItem item = null;
-
- Cursor itemCursor = adapter.getFeedItemCursor(Long.toString(itemId));
- if (itemCursor.moveToFirst()) {
- List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor);
- if (list.size() > 0) {
- item = list.get(0);
- loadFeedDataOfFeedItemlist(context, list);
- }
- }
- return item;
-
- }
-
- /**
- * Loads a specific FeedItem from the database.
- *
- * @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 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);
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- FeedItem item = getFeedItem(context, itemId, adapter);
- adapter.close();
- return item;
-
- }
-
- /**
- * 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);
- 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);
- item.setDescription(description);
- item.setContentEncoded(contentEncoded);
- }
- adapter.close();
- }
-
- /**
- * 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);
- 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 getNumberOfUnreadItems(final Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final int result = adapter.getNumberOfUnreadItems();
- 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);
- adapter.open();
- FeedImage result = getFeedImage(adapter, imageId);
- adapter.close();
- return result;
- }
-
- /**
- * Searches the DB for a FeedImage of the given id.
- *
- * @param id The id of the object
- * @return The found object
- */
- static FeedImage getFeedImage(PodDBAdapter adapter, final long id) {
- Cursor cursor = adapter.getImageCursor(id);
- if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
- throw new SQLException("No FeedImage found at index: " + id);
- }
- 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
- );
- cursor.close();
- return image;
- }
-
- /**
- * 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);
-
- 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);
- if (media != null && item != null) {
- media.setItem(item);
- item.setMedia(media);
- }
- }
-
- mediaCursor.close();
- adapter.close();
-
- return media;
- }
-
- /**
- * 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<FlattrThing> getFlattrQueue(Context context) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- List<FlattrThing> result = new ArrayList<FlattrThing>();
-
- // load feeds
- Cursor feedCursor = adapter.getFeedsInFlattrQueueCursor();
- if (feedCursor.moveToFirst()) {
- do {
- result.add(extractFeedFromCursorRow(adapter, feedCursor));
- } while (feedCursor.moveToNext());
- }
- feedCursor.close();
-
- //load feed items
- Cursor feedItemCursor = adapter.getFeedItemsInFlattrQueueCursor();
- result.addAll(extractItemlistFromCursor(adapter, feedItemCursor));
- feedItemCursor.close();
-
- adapter.close();
- Log.d(TAG, "Returning flattrQueueIterator for queue with " + result.size() + " items.");
- 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);
- adapter.open();
- List<Feed> feeds = getFeedList(adapter);
- int queueSize = adapter.getQueueSize();
- int numUnreadItems = adapter.getNumberOfUnreadItems();
- NavDrawerData result = new NavDrawerData(feeds, queueSize, numUnreadItems);
- adapter.close();
- return result;
- }
-
- public static class NavDrawerData {
- public List<Feed> feeds;
- public int queueSize;
- public int numUnreadItems;
-
- public NavDrawerData(List<Feed> feeds, int queueSize, int numUnreadItems) {
- this.feeds = feeds;
- this.queueSize = queueSize;
- this.numUnreadItems = numUnreadItems;
- }
- }
-}
diff --git a/src/de/danoeh/antennapod/storage/DBTasks.java b/src/de/danoeh/antennapod/storage/DBTasks.java
deleted file mode 100644
index a230ba797..000000000
--- a/src/de/danoeh/antennapod/storage/DBTasks.java
+++ /dev/null
@@ -1,895 +0,0 @@
-package de.danoeh.antennapod.storage;
-
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.asynctask.FlattrClickWorker;
-import de.danoeh.antennapod.asynctask.FlattrStatusFetcher;
-import de.danoeh.antennapod.feed.*;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.service.GpodnetSyncService;
-import de.danoeh.antennapod.service.download.DownloadStatus;
-import de.danoeh.antennapod.service.playback.PlaybackService;
-import de.danoeh.antennapod.util.DownloadError;
-import de.danoeh.antennapod.util.NetworkUtils;
-import de.danoeh.antennapod.util.QueueAccess;
-import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator;
-import de.danoeh.antennapod.util.exception.MediaFileNotFoundException;
-import de.danoeh.antennapod.util.flattr.FlattrUtils;
-
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Provides methods for doing common tasks that use DBReader and DBWriter.
- */
-public final class DBTasks {
- private static final String TAG = "DBTasks";
-
- /**
- * Executor service used by the autodownloadUndownloadedEpisodes method.
- */
- private static ExecutorService autodownloadExec;
-
- static {
- autodownloadExec = Executors.newSingleThreadExecutor(new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- Thread t = new Thread(r);
- t.setPriority(Thread.MIN_PRIORITY);
- return t;
- }
- });
- }
-
- private DBTasks() {
- }
-
- /**
- * Removes the feed with the given download url. This method should NOT be executed on the GUI thread.
- *
- * @param context Used for accessing the db
- * @param downloadUrl URL of the feed.
- */
- public static void removeFeedWithDownloadUrl(Context context, String downloadUrl) {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- Cursor cursor = adapter.getFeedCursorDownloadUrls();
- long feedID = 0;
- if (cursor.moveToFirst()) {
- do {
- if (cursor.getString(1).equals(downloadUrl)) {
- feedID = cursor.getLong(0);
- }
- } while (cursor.moveToNext());
- }
- cursor.close();
- adapter.close();
-
- if (feedID != 0) {
- try {
- DBWriter.deleteFeed(context, feedID).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- } else {
- Log.w(TAG, "removeFeedWithDownloadUrl: Could not find feed with url: " + downloadUrl);
- }
- }
-
- /**
- * Starts playback of a FeedMedia object's file. This method will build an Intent based on the given parameters to
- * start the {@link PlaybackService}.
- *
- * @param context Used for sending starting Services and Activities.
- * @param media The FeedMedia object.
- * @param showPlayer If true, starts the appropriate player activity ({@link de.danoeh.antennapod.activity.AudioplayerActivity}
- * or {@link de.danoeh.antennapod.activity.VideoplayerActivity}
- * @param startWhenPrepared Parameter for the {@link PlaybackService} start intent. If true, playback will start as
- * soon as the PlaybackService has finished loading the FeedMedia object's file.
- * @param shouldStream Parameter for the {@link PlaybackService} start intent. If true, the FeedMedia object's file
- * will be streamed, otherwise the downloaded file will be used. If the downloaded file cannot be
- * found, the PlaybackService will shutdown and the database entry of the FeedMedia object will be
- * corrected.
- */
- public static void playMedia(final Context context, final FeedMedia media,
- boolean showPlayer, boolean startWhenPrepared, boolean shouldStream) {
- try {
- if (!shouldStream) {
- if (media.fileExists() == false) {
- throw new MediaFileNotFoundException(
- "No episode was found at " + media.getFile_url(),
- media);
- }
- }
- // Start playback Service
- Intent launchIntent = new Intent(context, PlaybackService.class);
- launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
- launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
- startWhenPrepared);
- launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
- shouldStream);
- launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
- true);
- context.startService(launchIntent);
- if (showPlayer) {
- // Launch media player
- context.startActivity(PlaybackService.getPlayerActivityIntent(
- context, media));
- }
- DBWriter.addQueueItemAt(context, media.getItem().getId(), 0, false);
- } catch (MediaFileNotFoundException e) {
- e.printStackTrace();
- if (media.isPlaying()) {
- context.sendBroadcast(new Intent(
- PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
- }
- notifyMissingFeedMediaFile(context, media);
- }
- }
-
- private static AtomicBoolean isRefreshing = new AtomicBoolean(false);
-
- /**
- * Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still
- * enqueuing Feeds for download from a previous call
- *
- * @param context Might be used for accessing the database
- * @param feeds List of Feeds that should be refreshed.
- */
- public static void refreshAllFeeds(final Context context,
- final List<Feed> feeds) {
- if (isRefreshing.compareAndSet(false, true)) {
- new Thread() {
- public void run() {
- if (feeds != null) {
- refreshFeeds(context, feeds);
- } else {
- refreshFeeds(context, DBReader.getFeedList(context));
- }
- isRefreshing.set(false);
-
- if (FlattrUtils.hasToken()) {
- if (BuildConfig.DEBUG) Log.d(TAG, "Flattring all pending things.");
- new FlattrClickWorker(context).executeAsync(); // flattr pending things
-
- if (BuildConfig.DEBUG) Log.d(TAG, "Fetching flattr status.");
- new FlattrStatusFetcher(context).start();
-
- }
- GpodnetSyncService.sendSyncIntent(context);
- autodownloadUndownloadedItems(context);
- }
- }.start();
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Ignoring request to refresh all feeds: Refresh lock is locked");
- }
- }
-
- /**
- * Used by refreshExpiredFeeds to determine which feeds should be refreshed.
- * This method will use the value specified in the UserPreferences as the
- * expiration time.
- *
- * @param context Used for DB access.
- * @return A list of expired feeds. An empty list will be returned if there
- * are no expired feeds.
- */
- public static List<Feed> getExpiredFeeds(final Context context) {
- long millis = UserPreferences.getUpdateInterval();
-
- if (millis > 0) {
-
- List<Feed> feedList = DBReader.getExpiredFeedsList(context,
- millis);
- if (feedList.size() > 0) {
- refreshFeeds(context, feedList);
- }
- return feedList;
- } else {
- return new ArrayList<Feed>();
- }
- }
-
- /**
- * Refreshes expired Feeds in the list returned by the getExpiredFeedsList(Context, long) method in DBReader.
- * The expiration date parameter is determined by the update interval specified in {@link UserPreferences}.
- *
- * @param context Used for DB access.
- */
- public static void refreshExpiredFeeds(final Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Refreshing expired feeds");
-
- new Thread() {
- public void run() {
- refreshFeeds(context, getExpiredFeeds(context));
- }
- }.start();
- }
-
- private static void refreshFeeds(final Context context,
- final List<Feed> feedList) {
-
- for (Feed feed : feedList) {
- try {
- refreshFeed(context, feed);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DBWriter.addDownloadStatus(
- context,
- new DownloadStatus(feed, feed
- .getHumanReadableIdentifier(),
- DownloadError.ERROR_REQUEST_ERROR, false, e
- .getMessage()
- )
- );
- }
- }
-
- }
-
- /**
- * Updates a specific Feed.
- *
- * @param context Used for requesting the download.
- * @param feed The Feed object.
- */
- public static void refreshFeed(Context context, Feed feed)
- throws DownloadRequestException {
- Feed f;
- if (feed.getPreferences() == null) {
- f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle());
- } else {
- f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle(),
- feed.getPreferences().getUsername(), feed.getPreferences().getPassword());
- }
- f.setId(feed.getId());
- DownloadRequester.getInstance().downloadFeed(context, f);
- }
-
- /**
- * Notifies the database about a missing FeedImage file. This method will attempt to re-download the file.
- *
- * @param context Used for requesting the download.
- * @param image The FeedImage object.
- */
- public static void notifyInvalidImageFile(final Context context,
- final FeedImage image) {
- Log.i(TAG,
- "The DB was notified about an invalid image download. It will now try to re-download the image file");
- try {
- DownloadRequester.getInstance().downloadImage(context, image);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- Log.w(TAG, "Failed to download invalid feed image");
- }
- }
-
- /**
- * Notifies the database about a missing FeedMedia file. This method will correct the FeedMedia object's values in the
- * DB and send a FeedUpdateBroadcast.
- */
- public static void notifyMissingFeedMediaFile(final Context context,
- final FeedMedia media) {
- Log.i(TAG,
- "The feedmanager was notified about a missing episode. It will update its database now.");
- media.setDownloaded(false);
- media.setFile_url(null);
- DBWriter.setFeedMedia(context, media);
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
- }
-
- /**
- * Request the download of all objects in the queue. from a separate Thread.
- *
- * @param context Used for requesting the download an accessing the database.
- */
- public static void downloadAllItemsInQueue(final Context context) {
- new Thread() {
- public void run() {
- List<FeedItem> queue = DBReader.getQueue(context);
- if (!queue.isEmpty()) {
- try {
- downloadFeedItems(context,
- queue.toArray(new FeedItem[queue.size()]));
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- }
- }
- }
- }.start();
- }
-
- /**
- * Requests the download of a list of FeedItem objects.
- *
- * @param context Used for requesting the download and accessing the DB.
- * @param items The FeedItem objects.
- */
- public static void downloadFeedItems(final Context context,
- FeedItem... items) throws DownloadRequestException {
- downloadFeedItems(true, context, items);
- }
-
- private static void downloadFeedItems(boolean performAutoCleanup,
- final Context context, final FeedItem... items)
- throws DownloadRequestException {
- final DownloadRequester requester = DownloadRequester.getInstance();
-
- if (performAutoCleanup) {
- new Thread() {
-
- @Override
- public void run() {
- performAutoCleanup(context,
- getPerformAutoCleanupArgs(context, items.length));
- }
-
- }.start();
- }
- for (FeedItem item : items) {
- if (item.getMedia() != null
- && !requester.isDownloadingFile(item.getMedia())
- && !item.getMedia().isDownloaded()) {
- if (items.length > 1) {
- try {
- requester.downloadMedia(context, item.getMedia());
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DBWriter.addDownloadStatus(context,
- new DownloadStatus(item.getMedia(), item
- .getMedia()
- .getHumanReadableIdentifier(),
- DownloadError.ERROR_REQUEST_ERROR,
- false, e.getMessage()
- )
- );
- }
- } else {
- requester.downloadMedia(context, item.getMedia());
- }
- }
- }
- }
-
- private static int getNumberOfUndownloadedEpisodes(
- final List<FeedItem> queue, final List<FeedItem> unreadItems) {
- int counter = 0;
- for (FeedItem item : queue) {
- if (item.hasMedia() && !item.getMedia().isDownloaded()
- && !item.getMedia().isPlaying()
- && item.getFeed().getPreferences().getAutoDownload()) {
- counter++;
- }
- }
- for (FeedItem item : unreadItems) {
- if (item.hasMedia() && !item.getMedia().isDownloaded()
- && item.getFeed().getPreferences().getAutoDownload()) {
- counter++;
- }
- }
- return counter;
- }
-
- /**
- * Looks for undownloaded episodes in the queue or list of unread items and request a download if
- * 1. Network is available
- * 2. There is free space in the episode cache
- * This method is executed on an internal single thread executor.
- *
- * @param context Used for accessing the DB.
- * @param mediaIds If this list is not empty, the method will only download a candidate for automatic downloading if
- * its media ID is in the mediaIds list.
- * @return A Future that can be used for waiting for the methods completion.
- */
- public static Future<?> autodownloadUndownloadedItems(final Context context, final long... mediaIds) {
- return autodownloadExec.submit(new Runnable() {
- @Override
- public void run() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Performing auto-dl of undownloaded episodes");
- if (NetworkUtils.autodownloadNetworkAvailable(context)
- && UserPreferences.isEnableAutodownload()) {
- final List<FeedItem> queue = DBReader.getQueue(context);
- final List<FeedItem> unreadItems = DBReader
- .getUnreadItemsList(context);
-
- int undownloadedEpisodes = getNumberOfUndownloadedEpisodes(queue,
- unreadItems);
- int downloadedEpisodes = DBReader
- .getNumberOfDownloadedEpisodes(context);
- int deletedEpisodes = performAutoCleanup(context,
- getPerformAutoCleanupArgs(context, undownloadedEpisodes));
- int episodeSpaceLeft = undownloadedEpisodes;
- boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences
- .getEpisodeCacheSizeUnlimited();
-
- if (!cacheIsUnlimited
- && UserPreferences.getEpisodeCacheSize() < downloadedEpisodes
- + undownloadedEpisodes) {
- episodeSpaceLeft = UserPreferences.getEpisodeCacheSize()
- - (downloadedEpisodes - deletedEpisodes);
- }
-
- Arrays.sort(mediaIds); // sort for binary search
- final boolean ignoreMediaIds = mediaIds.length == 0;
- List<FeedItem> itemsToDownload = new ArrayList<FeedItem>();
-
- if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
- for (int i = 0; i < queue.size(); i++) { // ignore playing item
- FeedItem item = queue.get(i);
- long mediaId = (item.hasMedia()) ? item.getMedia().getId() : -1;
- if ((ignoreMediaIds || Arrays.binarySearch(mediaIds, mediaId) >= 0)
- && item.hasMedia()
- && !item.getMedia().isDownloaded()
- && !item.getMedia().isPlaying()
- && item.getFeed().getPreferences().getAutoDownload()) {
- itemsToDownload.add(item);
- episodeSpaceLeft--;
- undownloadedEpisodes--;
- if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
- break;
- }
- }
- }
- }
-
- if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
- for (FeedItem item : unreadItems) {
- long mediaId = (item.hasMedia()) ? item.getMedia().getId() : -1;
- if ((ignoreMediaIds || Arrays.binarySearch(mediaIds, mediaId) >= 0)
- && item.hasMedia()
- && !item.getMedia().isDownloaded()
- && item.getFeed().getPreferences().getAutoDownload()) {
- itemsToDownload.add(item);
- episodeSpaceLeft--;
- undownloadedEpisodes--;
- if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
- break;
- }
- }
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Enqueueing " + itemsToDownload.size()
- + " items for download");
-
- try {
- downloadFeedItems(false, context,
- itemsToDownload.toArray(new FeedItem[itemsToDownload
- .size()])
- );
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- }
-
- }
- }
- });
-
- }
-
- private static int getPerformAutoCleanupArgs(Context context,
- final int episodeNumber) {
- if (episodeNumber >= 0
- && UserPreferences.getEpisodeCacheSize() != UserPreferences
- .getEpisodeCacheSizeUnlimited()) {
- int downloadedEpisodes = DBReader
- .getNumberOfDownloadedEpisodes(context);
- if (downloadedEpisodes + episodeNumber >= UserPreferences
- .getEpisodeCacheSize()) {
-
- return downloadedEpisodes + episodeNumber
- - UserPreferences.getEpisodeCacheSize();
- }
- }
- return 0;
- }
-
- /**
- * Removed downloaded episodes outside of the queue if the episode cache is full. Episodes with a smaller
- * 'playbackCompletionDate'-value will be deleted first.
- * <p/>
- * This method should NOT be executed on the GUI thread.
- *
- * @param context Used for accessing the DB.
- */
- public static void performAutoCleanup(final Context context) {
- performAutoCleanup(context, getPerformAutoCleanupArgs(context, 0));
- }
-
- private static int performAutoCleanup(final Context context,
- final int episodeNumber) {
- List<FeedItem> candidates = new ArrayList<FeedItem>();
- List<FeedItem> downloadedItems = DBReader.getDownloadedItems(context);
- QueueAccess queue = QueueAccess.IDListAccess(DBReader.getQueueIDList(context));
- List<FeedItem> delete;
- for (FeedItem item : downloadedItems) {
- if (item.hasMedia() && item.getMedia().isDownloaded()
- && !queue.contains(item.getId()) && item.isRead()) {
- candidates.add(item);
- }
-
- }
-
- Collections.sort(candidates, new Comparator<FeedItem>() {
- @Override
- public int compare(FeedItem lhs, FeedItem rhs) {
- Date l = lhs.getMedia().getPlaybackCompletionDate();
- Date r = rhs.getMedia().getPlaybackCompletionDate();
-
- if (l == null) {
- l = new Date(0);
- }
- if (r == null) {
- r = new Date(0);
- }
- return l.compareTo(r);
- }
- });
-
- if (candidates.size() > episodeNumber) {
- delete = candidates.subList(0, episodeNumber);
- } else {
- delete = candidates;
- }
-
- for (FeedItem item : delete) {
- try {
- DBWriter.deleteFeedMediaOfItem(context, item.getMedia().getId()).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
-
- int counter = delete.size();
-
- if (BuildConfig.DEBUG)
- Log.d(TAG, String.format(
- "Auto-delete deleted %d episodes (%d requested)", counter,
- episodeNumber));
-
- return counter;
- }
-
- /**
- * Adds all FeedItem objects whose 'read'-attribute is false to the queue in a separate thread.
- */
- public static void enqueueAllNewItems(final Context context) {
- long[] unreadItems = DBReader.getUnreadItemIds(context);
- DBWriter.addQueueItem(context, unreadItems);
- }
-
- /**
- * Returns the successor of a FeedItem in the queue.
- *
- * @param context Used for accessing the DB.
- * @param itemId ID of the FeedItem
- * @param queue Used for determining the successor of the item. If this parameter is null, the method will load
- * the queue from the database in the same thread.
- * @return Successor of the FeedItem or null if the FeedItem is not in the queue or has no successor.
- */
- public static FeedItem getQueueSuccessorOfItem(Context context,
- final long itemId, List<FeedItem> queue) {
- FeedItem result = null;
- if (queue == null) {
- queue = DBReader.getQueue(context);
- }
- if (queue != null) {
- Iterator<FeedItem> iterator = queue.iterator();
- while (iterator.hasNext()) {
- FeedItem item = iterator.next();
- if (item.getId() == itemId) {
- if (iterator.hasNext()) {
- result = iterator.next();
- }
- break;
- }
- }
- }
- return result;
- }
-
- /**
- * Loads the queue from the database and checks if the specified FeedItem is in the queue.
- * This method should NOT be executed in the GUI thread.
- *
- * @param context Used for accessing the DB.
- * @param feedItemId ID of the FeedItem
- */
- public static boolean isInQueue(Context context, final long feedItemId) {
- List<Long> queue = DBReader.getQueueIDList(context);
- return QueueAccess.IDListAccess(queue).contains(feedItemId);
- }
-
- private static Feed searchFeedByIdentifyingValueOrID(Context context, PodDBAdapter adapter,
- Feed feed) {
- if (feed.getId() != 0) {
- return DBReader.getFeed(context, feed.getId(), adapter);
- } else {
- List<Feed> feeds = DBReader.getFeedList(context);
- for (Feed f : feeds) {
- if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) {
- f.setItems(DBReader.getFeedItemList(context, f));
- return f;
- }
- }
- }
- return null;
- }
-
- /**
- * Get a FeedItem by its identifying value.
- */
- private static FeedItem searchFeedItemByIdentifyingValue(Feed feed,
- String identifier) {
- for (FeedItem item : feed.getItems()) {
- if (item.getIdentifyingValue().equals(identifier)) {
- return item;
- }
- }
- return null;
- }
-
- /**
- * Adds new Feeds to the database or updates the old versions if they already exists. If another Feed with the same
- * identifying value already exists, this method will add new FeedItems from the new Feed to the existing Feed.
- * These FeedItems will be marked as unread.
- * <p/>
- * This method can update multiple feeds at once. Submitting a feed twice in the same method call can result in undefined behavior.
- * <p/>
- * This method should NOT be executed on the GUI thread.
- *
- * @param context Used for accessing the DB.
- * @param newFeeds The new Feed objects.
- * @return The updated Feeds from the database if it already existed, or the new Feed from the parameters otherwise.
- */
- public static synchronized Feed[] updateFeed(final Context context,
- final Feed... newFeeds) {
- List<Feed> newFeedsList = new ArrayList<Feed>();
- List<Feed> updatedFeedsList = new ArrayList<Feed>();
- Feed[] resultFeeds = new Feed[newFeeds.length];
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
-
- for (int feedIdx = 0; feedIdx < newFeeds.length; feedIdx++) {
-
- final Feed newFeed = newFeeds[feedIdx];
-
- // Look up feed in the feedslist
- final Feed savedFeed = searchFeedByIdentifyingValueOrID(context, adapter,
- newFeed);
- if (savedFeed == null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Found no existing Feed with title "
- + newFeed.getTitle() + ". Adding as new one."
- );
- // Add a new Feed
- newFeedsList.add(newFeed);
- resultFeeds[feedIdx] = newFeed;
- } else {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed with title " + newFeed.getTitle()
- + " already exists. Syncing new with existing one.");
-
- Collections.sort(newFeed.getItems(), new FeedItemPubdateComparator());
- if (savedFeed.compareWithOther(newFeed)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Feed has updated attribute values. Updating old feed's attributes");
- savedFeed.updateFromOther(newFeed);
- }
- if (savedFeed.getPreferences().compareWithOther(newFeed.getPreferences())) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences");
- savedFeed.getPreferences().updateFromOther(newFeed.getPreferences());
- }
- // Look for new or updated Items
- for (int idx = 0; idx < newFeed.getItems().size(); idx++) {
- final FeedItem item = newFeed.getItems().get(idx);
- FeedItem oldItem = searchFeedItemByIdentifyingValue(savedFeed,
- item.getIdentifyingValue());
- if (oldItem == null) {
- // item is new
- final int i = idx;
- item.setFeed(savedFeed);
- savedFeed.getItems().add(i, item);
- item.setRead(false);
- } else {
- oldItem.updateFromOther(item);
- }
- }
- // update attributes
- savedFeed.setLastUpdate(newFeed.getLastUpdate());
- savedFeed.setType(newFeed.getType());
-
- updatedFeedsList.add(savedFeed);
- resultFeeds[feedIdx] = savedFeed;
- }
- }
-
- adapter.close();
-
- try {
- DBWriter.addNewFeed(context, newFeedsList.toArray(new Feed[newFeedsList.size()])).get();
- DBWriter.setCompleteFeed(context, updatedFeedsList.toArray(new Feed[updatedFeedsList.size()])).get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
-
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
-
- return resultFeeds;
- }
-
- /**
- * Searches the titles of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string.
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemTitle(final Context context,
- final long feedID, final String query) {
- return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemTitles(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
- DBReader.loadFeedDataOfFeedItemlist(context, items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches the descriptions of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemDescription(final Context context,
- final long feedID, final String query) {
- return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemDescriptions(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
- DBReader.loadFeedDataOfFeedItemlist(context, items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches the contentEncoded-value of FeedItems of a specific Feed for a given
- * string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemContentEncoded(final Context context,
- final long feedID, final String query) {
- return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemContentEncoded(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
- DBReader.loadFeedDataOfFeedItemlist(context, items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * Searches chapters of the FeedItems of a specific Feed for a given string.
- *
- * @param context Used for accessing the DB.
- * @param feedID The id of the feed whose items should be searched.
- * @param query The search string
- * @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
- */
- public static FutureTask<List<FeedItem>> searchFeedItemChapters(final Context context,
- final long feedID, final String query) {
- return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
- @Override
- public void execute(PodDBAdapter adapter) {
- Cursor searchResult = adapter.searchItemChapters(feedID,
- query);
- List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
- DBReader.loadFeedDataOfFeedItemlist(context, items);
- setResult(items);
- searchResult.close();
- }
- });
- }
-
- /**
- * A runnable which should be used for database queries. The onCompletion
- * method is executed on the database executor to handle Cursors correctly.
- * This class automatically creates a PodDBAdapter object and closes it when
- * it is no longer in use.
- */
- static abstract class QueryTask<T> implements Callable<T> {
- private T result;
- private Context context;
-
- public QueryTask(Context context) {
- this.context = context;
- }
-
- @Override
- public T call() throws Exception {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- execute(adapter);
- adapter.close();
- return result;
- }
-
- public abstract void execute(PodDBAdapter adapter);
-
- protected void setResult(T result) {
- this.result = result;
- }
- }
-
- /**
- * Adds the given FeedItem to the flattr queue if the user is logged in. Otherwise, a dialog
- * will be opened that lets the user go either to the login screen or the website of the flattr thing.
- *
- * @param context
- * @param item
- */
- public static void flattrItemIfLoggedIn(Context context, FeedItem item) {
- if (FlattrUtils.hasToken()) {
- item.getFlattrStatus().setFlattrQueue();
- DBWriter.setFlattredStatus(context, item, true);
- } else {
- FlattrUtils.showNoTokenDialogOrRedirect(context, item.getPaymentLink());
- }
- }
-
- /**
- * Adds the given Feed to the flattr queue if the user is logged in. Otherwise, a dialog
- * will be opened that lets the user go either to the login screen or the website of the flattr thing.
- *
- * @param context
- * @param feed
- */
- public static void flattrFeedIfLoggedIn(Context context, Feed feed) {
- if (FlattrUtils.hasToken()) {
- feed.getFlattrStatus().setFlattrQueue();
- DBWriter.setFlattredStatus(context, feed, true);
- } else {
- FlattrUtils.showNoTokenDialogOrRedirect(context, feed.getPaymentLink());
- }
- }
-
-}
diff --git a/src/de/danoeh/antennapod/storage/DBWriter.java b/src/de/danoeh/antennapod/storage/DBWriter.java
deleted file mode 100644
index 9916ac97f..000000000
--- a/src/de/danoeh/antennapod/storage/DBWriter.java
+++ /dev/null
@@ -1,974 +0,0 @@
-package de.danoeh.antennapod.storage;
-
-import android.app.backup.BackupManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.asynctask.FlattrClickWorker;
-import de.danoeh.antennapod.feed.*;
-import de.danoeh.antennapod.preferences.GpodnetPreferences;
-import de.danoeh.antennapod.preferences.PlaybackPreferences;
-import de.danoeh.antennapod.service.download.DownloadStatus;
-import de.danoeh.antennapod.service.playback.PlaybackService;
-import de.danoeh.antennapod.util.QueueAccess;
-import de.danoeh.antennapod.util.flattr.FlattrStatus;
-import de.danoeh.antennapod.util.flattr.FlattrThing;
-import de.danoeh.antennapod.util.flattr.SimpleFlattrThing;
-import org.shredzone.flattr4j.model.Flattr;
-
-import java.io.File;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ThreadFactory;
-
-/**
- * Provides methods for writing data to AntennaPod's database.
- * In general, DBWriter-methods will be executed on an internal ExecutorService.
- * Some methods return a Future-object which the caller can use for waiting for the method's completion. The returned Future's
- * will NOT contain any results.
- * The caller can also use the {@link EventDistributor} in order to be notified about the method's completion asynchronously.
- * 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;
- }
- });
- }
-
- private DBWriter() {
- }
-
- /**
- * Deletes a downloaded FeedMedia file from the storage device.
- *
- * @param context A context that is used for opening a database connection.
- * @param mediaId ID of the FeedMedia object whose downloaded file should be deleted.
- */
- 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);
- 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));
- }
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Deleting File. Result: " + result);
- EventDistributor.getInstance().sendQueueUpdateBroadcast();
- EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
- }
- }
- });
- }
-
- /**
- * Deletes a Feed and all downloaded files of its components like images and downloaded episodes.
- *
- * @param context A context that is used for opening a database connection.
- * @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();
- }
-
- // 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<FeedItem> queue = DBReader.getQueue(context);
- boolean queueWasModified = false;
- if (feed.getItems() == null) {
- DBReader.getFeedItemList(context, feed);
- }
-
- for (FeedItem item : feed.getItems()) {
- queueWasModified |= queue.remove(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());
- }
- }
- }
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- if (queueWasModified) {
- adapter.setQueue(queue);
- }
- adapter.removeFeed(feed);
- adapter.close();
-
- GpodnetPreferences.addRemovedFeed(feed.getDownload_url());
- EventDistributor.getInstance().sendFeedUpdateBroadcast();
-
- BackupManager backupManager = new BackupManager(context);
- backupManager.dataChanged();
- }
- }
- });
- }
-
- /**
- * 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();
- }
- });
- }
-
- /**
- * Adds a FeedMedia object to the playback history. A FeedMedia object is in the playback history if
- * 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);
-
- PodDBAdapter adapter = new PodDBAdapter(context);
- 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();
- }
- });
-
- }
-
- /**
- * Inserts a FeedItem in the queue at the specified index. The 'read'-attribute of the FeedItem will be set to
- * true. If the FeedItem is already in the queue, the queue will not be modified.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId ID of the FeedItem that should be added to the queue.
- * @param index Destination index. Must be in range 0..queue.size()
- * @param performAutoDownload True if an auto-download process should be started after the operation
- * @throws IndexOutOfBoundsException if index < 0 || index >= queue.size()
- */
- 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<FeedItem> queue = DBReader
- .getQueue(context, adapter);
- FeedItem item = null;
-
- if (queue != null) {
- boolean queueModified = false;
- boolean unreadItemsModified = false;
-
- if (!itemListContains(queue, itemId)) {
- item = DBReader.getFeedItem(context, itemId);
- if (item != null) {
- queue.add(index, item);
- queueModified = true;
- if (!item.isRead()) {
- item.setRead(true);
- unreadItemsModified = true;
- }
- }
- }
- if (queueModified) {
- adapter.setQueue(queue);
- EventDistributor.getInstance()
- .sendQueueUpdateBroadcast();
- }
- if (unreadItemsModified && item != null) {
- adapter.setSingleFeedItem(item);
- EventDistributor.getInstance()
- .sendUnreadItemsUpdateBroadcast();
- }
- }
- adapter.close();
- if (performAutoDownload) {
- DBTasks.autodownloadUndownloadedItems(context);
- }
-
- }
- });
-
- }
-
- /**
- * Appends FeedItem objects to the end of the queue. The 'read'-attribute of all items will be set to true.
- * If a FeedItem is already in the queue, the FeedItem will not change its position in the queue.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemIds IDs of the FeedItem objects that should be added to the queue.
- */
- public static Future<?> addQueueItem(final Context context,
- final long... itemIds) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- if (itemIds.length > 0) {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final List<FeedItem> queue = DBReader.getQueue(context,
- adapter);
-
- if (queue != null) {
- boolean queueModified = false;
- boolean unreadItemsModified = false;
- List<FeedItem> itemsToSave = new LinkedList<FeedItem>();
- for (int i = 0; i < itemIds.length; i++) {
- if (!itemListContains(queue, itemIds[i])) {
- final FeedItem item = DBReader.getFeedItem(
- context, itemIds[i]);
-
- if (item != null) {
- queue.add(item);
- queueModified = true;
- if (!item.isRead()) {
- item.setRead(true);
- itemsToSave.add(item);
- unreadItemsModified = true;
- }
- }
- }
- }
- if (queueModified) {
- adapter.setQueue(queue);
- EventDistributor.getInstance()
- .sendQueueUpdateBroadcast();
- }
- if (unreadItemsModified) {
- adapter.setFeedItemlist(itemsToSave);
- EventDistributor.getInstance()
- .sendUnreadItemsUpdateBroadcast();
- }
- }
- adapter.close();
- DBTasks.autodownloadUndownloadedItems(context);
- }
- }
- });
-
- }
-
- /**
- * 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();
-
- EventDistributor.getInstance().sendQueueUpdateBroadcast();
- }
- });
- }
-
- /**
- * Removes a FeedItem object from the queue.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId ID of the FeedItem that should be removed.
- * @param performAutoDownload true if an auto-download process should be started after the operation.
- */
- public static Future<?> removeQueueItem(final Context context,
- final long itemId, final boolean performAutoDownload) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final List<FeedItem> queue = DBReader
- .getQueue(context, adapter);
- FeedItem item = null;
-
- if (queue != null) {
- boolean queueModified = false;
- QueueAccess queueAccess = QueueAccess.ItemListAccess(queue);
- if (queueAccess.contains(itemId)) {
- item = DBReader.getFeedItem(context, itemId);
- if (item != null) {
- queueModified = queueAccess.remove(itemId);
- }
- }
- if (queueModified) {
- adapter.setQueue(queue);
- EventDistributor.getInstance()
- .sendQueueUpdateBroadcast();
- } else {
- 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);
- }
- }
- });
-
- }
-
- /**
- * 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 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() {
- List<Long> queueIdList = DBReader.getQueueIDList(context);
- int currentLocation = 0;
- for (long id : queueIdList) {
- if (id == itemId) {
- moveQueueItemHelper(context, currentLocation, 0, broadcastUpdate);
- return;
- }
- currentLocation++;
- }
- 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 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,
- final boolean broadcastUpdate) {
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- List<Long> queueIdList = DBReader.getQueueIDList(context);
- int currentLocation = 0;
- for (long id : queueIdList) {
- if (id == itemId) {
- moveQueueItemHelper(context, currentLocation, queueIdList.size() - 1,
- broadcastUpdate);
- return;
- }
- currentLocation++;
- }
- Log.e(TAG, "moveQueueItemToBottom: item not found");
- }
- });
- }
-
- /**
- * 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,
- final int to, final boolean broadcastUpdate) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- moveQueueItemHelper(context, from, to, broadcastUpdate);
- }
- });
- }
-
- /**
- * Changes the position of a FeedItem in the queue.
- * <p/>
- * 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,
- final int to, final boolean broadcastUpdate) {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- final List<FeedItem> queue = DBReader
- .getQueue(context, adapter);
-
- if (queue != null) {
- if (from >= 0 && from < queue.size() && to >= 0
- && to < queue.size()) {
-
- final FeedItem item = queue.remove(from);
- queue.add(to, item);
-
- adapter.setQueue(queue);
- if (broadcastUpdate) {
- EventDistributor.getInstance()
- .sendQueueUpdateBroadcast();
- }
-
- }
- } else {
- Log.e(TAG, "moveQueueItemHelper: Could not load queue");
- }
- adapter.close();
- }
-
- /**
- * 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 read New value of the 'read'-attribute
- * @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<?> markItemRead(Context context, FeedItem item, boolean read, boolean resetMediaPosition) {
- long mediaId = (item.hasMedia()) ? item.getMedia().getId() : 0;
- return markItemRead(context, item.getId(), read, mediaId, resetMediaPosition);
- }
-
- /**
- * Sets the 'read'-attribute of a FeedItem to the specified value.
- *
- * @param context A context that is used for opening a database connection.
- * @param itemId ID of the FeedItem
- * @param read New value of the 'read'-attribute
- */
- public static Future<?> markItemRead(final Context context, final long itemId,
- final boolean read) {
- return markItemRead(context, itemId, read, 0, false);
- }
-
- private static Future<?> markItemRead(final Context context, final long itemId,
- final boolean read, final long mediaId,
- final boolean resetMediaPosition) {
- return dbExec.submit(new Runnable() {
-
- @Override
- public void run() {
- final PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setFeedItemRead(read, itemId, mediaId,
- resetMediaPosition);
- adapter.close();
-
- 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(true, itemIds);
- adapter.close();
-
- 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(true, itemIds);
- adapter.close();
-
- 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();
-
- for (Feed feed : feeds) {
- GpodnetPreferences.addAddedFeed(feed.getDownload_url());
- }
-
- 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();
-
- }
- });
-
- }
-
- /**
- * 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();
- }
- });
- }
-
- /**
- * 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();
- }
- });
- }
-
- /**
- * 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();
- }
- });
- }
-
- /**
- * 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();
- }
- });
- }
-
- /**
- * 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<String, String> 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));
-
- 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();
- }
- });
- }
-
- private static boolean itemListContains(List<FeedItem> items, long itemId) {
- for (FeedItem item : items) {
- if (item.getId() == itemId) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Saves the FlattrStatus of a FeedItem object in the database.
- *
- * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
- */
- 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();
- }
- }
- });
- }
-
- /**
- * Saves the FlattrStatus of a Feed object in the database.
- *
- * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
- */
- 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();
- }
- }
- });
- }
-
- /**
- * format an url for querying the database
- * (postfix a / and apply percent-encoding)
- */
- private static String formatURIForQuery(String uri) {
- try {
- return URLEncoder.encode(uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- Log.e(TAG, e.getMessage());
- return "";
- }
- }
-
-
- /**
- * Set flattr status of the passed thing (either a FeedItem or a Feed)
- *
- * @param context
- * @param thing
- * @param startFlattrClickWorker true if FlattrClickWorker should be started after the FlattrStatus has been saved
- * @return
- */
- public static Future<?> setFlattredStatus(Context context, FlattrThing thing, boolean startFlattrClickWorker) {
- // must propagate this to back db
- if (thing instanceof FeedItem)
- return setFeedItemFlattrStatus(context, (FeedItem) thing, startFlattrClickWorker);
- 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
- Log.e(TAG, "flattrQueue processing - thing is neither FeedItem nor Feed nor SimpleFlattrThing");
-
- return null;
- }
-
- /**
- * Reset flattr status to unflattrd for all items
- */
- public static Future<?> clearAllFlattrStatus(final Context context) {
- Log.d(TAG, "clearAllFlattrStatus()");
- return dbExec.submit(new Runnable() {
- @Override
- public void run() {
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.clearAllFlattrStatus();
- adapter.close();
- }
- });
- }
-
- /**
- * 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<Flattr> flattrList) {
- Log.d(TAG, "setFlattredStatus to status retrieved from flattr api running with " + flattrList.size() + " items");
- // clear flattr status in db
- clearAllFlattrStatus(context);
-
- // 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();
- }
- });
- }
-}
diff --git a/src/de/danoeh/antennapod/storage/DownloadRequestException.java b/src/de/danoeh/antennapod/storage/DownloadRequestException.java
deleted file mode 100644
index 0ef766e58..000000000
--- a/src/de/danoeh/antennapod/storage/DownloadRequestException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package de.danoeh.antennapod.storage;
-
-/**
- * Thrown by the DownloadRequester if a download request contains invalid data
- * or something went wrong while processing the request.
- */
-public class DownloadRequestException extends Exception {
-
- public DownloadRequestException() {
- super();
- }
-
- public DownloadRequestException(String detailMessage, Throwable throwable) {
- super(detailMessage, throwable);
- }
-
- public DownloadRequestException(String detailMessage) {
- super(detailMessage);
- }
-
- public DownloadRequestException(Throwable throwable) {
- super(throwable);
- }
-
-}
diff --git a/src/de/danoeh/antennapod/storage/DownloadRequester.java b/src/de/danoeh/antennapod/storage/DownloadRequester.java
deleted file mode 100644
index d305c572b..000000000
--- a/src/de/danoeh/antennapod/storage/DownloadRequester.java
+++ /dev/null
@@ -1,367 +0,0 @@
-package de.danoeh.antennapod.storage;
-
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-import android.webkit.URLUtil;
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.feed.*;
-import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.service.download.DownloadRequest;
-import de.danoeh.antennapod.service.download.DownloadService;
-import de.danoeh.antennapod.util.FileNameGenerator;
-import de.danoeh.antennapod.util.URLChecker;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-
-import java.io.File;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-
-/**
- * Sends download requests to the DownloadService. This class should always be used for starting downloads,
- * otherwise they won't work correctly.
- */
-public class DownloadRequester {
- private static final String TAG = "DownloadRequester";
-
- public static final String IMAGE_DOWNLOADPATH = "images/";
- public static final String FEED_DOWNLOADPATH = "cache/";
- public static final String MEDIA_DOWNLOADPATH = "media/";
-
- private static DownloadRequester downloader;
-
- Map<String, DownloadRequest> downloads;
-
- private DownloadRequester() {
- downloads = new ConcurrentHashMap<String, DownloadRequest>();
- }
-
- public static synchronized DownloadRequester getInstance() {
- if (downloader == null) {
- downloader = new DownloadRequester();
- }
- return downloader;
- }
-
- /**
- * Starts a new download with the given DownloadRequest. This method should only
- * be used from outside classes if the DownloadRequest was created by the DownloadService to
- * ensure that the data is valid. Use downloadFeed(), downloadImage() or downloadMedia() instead.
- *
- * @param context Context object for starting the DownloadService
- * @param request The DownloadRequest. If another DownloadRequest with the same source URL is already stored, this method
- * call will return false.
- * @return True if the download request was accepted, false otherwise.
- */
- public boolean download(Context context, DownloadRequest request) {
- Validate.notNull(context);
- Validate.notNull(request);
-
- if (downloads.containsKey(request.getSource())) {
- if (BuildConfig.DEBUG) Log.i(TAG, "DownloadRequest is already stored.");
- return false;
- }
- downloads.put(request.getSource(), request);
-
- Intent launchIntent = new Intent(context, DownloadService.class);
- launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
- context.startService(launchIntent);
- EventDistributor.getInstance().sendDownloadQueuedBroadcast();
- return true;
- }
-
- private void download(Context context, FeedFile item, File dest,
- boolean overwriteIfExists, String username, String password, boolean deleteOnFailure) {
- if (!isDownloadingFile(item)) {
- if (!isFilenameAvailable(dest.toString()) || (deleteOnFailure && dest.exists())) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Filename already used.");
- if (isFilenameAvailable(dest.toString()) && overwriteIfExists) {
- boolean result = dest.delete();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Deleting file. Result: " + result);
- } else {
- // find different name
- File newDest = null;
- for (int i = 1; i < Integer.MAX_VALUE; i++) {
- String newName = FilenameUtils.getBaseName(dest
- .getName())
- + "-"
- + i
- + FilenameUtils.EXTENSION_SEPARATOR
- + FilenameUtils.getExtension(dest.getName());
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Testing filename " + newName);
- newDest = new File(dest.getParent(), newName);
- if (!newDest.exists()
- && isFilenameAvailable(newDest.toString())) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "File doesn't exist yet. Using "
- + newName);
- break;
- }
- }
- if (newDest != null) {
- dest = newDest;
- }
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Requesting download of url " + item.getDownload_url());
- item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
-
- DownloadRequest request = new DownloadRequest(dest.toString(),
- URLChecker.prepareURL(item.getDownload_url()), item.getHumanReadableIdentifier(),
- item.getId(), item.getTypeAsInt(), username, password, deleteOnFailure);
-
- download(context, request);
- } else {
- Log.e(TAG, "URL " + item.getDownload_url()
- + " is already being downloaded");
- }
- }
-
- /**
- * Returns true if a filename is available and false if it has already been
- * taken by another requested download.
- */
- private boolean isFilenameAvailable(String path) {
- for (String key : downloads.keySet()) {
- DownloadRequest r = downloads.get(key);
- if (StringUtils.equals(r.getDestination(), path)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, path
- + " is already used by another requested download");
- return false;
- }
- }
- if (BuildConfig.DEBUG)
- Log.d(TAG, path + " is available as a download destination");
- return true;
- }
-
- public void downloadFeed(Context context, Feed feed)
- throws DownloadRequestException {
- if (feedFileValid(feed)) {
- String username = (feed.getPreferences() != null) ? feed.getPreferences().getUsername() : null;
- String password = (feed.getPreferences() != null) ? feed.getPreferences().getPassword() : null;
-
- download(context, feed, new File(getFeedfilePath(context),
- getFeedfileName(feed)), true, username, password, true);
- }
- }
-
- public void downloadImage(Context context, FeedImage image)
- throws DownloadRequestException {
- if (feedFileValid(image)) {
- download(context, image, new File(getImagefilePath(context),
- getImagefileName(image)), false, null, null, false);
- }
- }
-
- public void downloadMedia(Context context, FeedMedia feedmedia)
- throws DownloadRequestException {
- if (feedFileValid(feedmedia)) {
- Feed feed = feedmedia.getItem().getFeed();
- String username;
- String password;
- if (feed != null && feed.getPreferences() != null) {
- username = feed.getPreferences().getUsername();
- password = feed.getPreferences().getPassword();
- } else {
- username = null;
- password = null;
- }
-
- File dest;
- if (feedmedia.getFile_url() != null) {
- dest = new File(feedmedia.getFile_url());
- } else {
- dest = new File(getMediafilePath(context, feedmedia),
- getMediafilename(feedmedia));
- }
- download(context, feedmedia,
- dest, false, username, password, false
- );
- }
- }
-
- /**
- * Throws a DownloadRequestException if the feedfile or the download url of
- * the feedfile is null.
- *
- * @throws DownloadRequestException
- */
- private boolean feedFileValid(FeedFile f) throws DownloadRequestException {
- if (f == null) {
- throw new DownloadRequestException("Feedfile was null");
- } else if (f.getDownload_url() == null) {
- throw new DownloadRequestException("File has no download URL");
- } else {
- return true;
- }
- }
-
- /**
- * Cancels a running download.
- */
- public void cancelDownload(final Context context, final FeedFile f) {
- cancelDownload(context, f.getDownload_url());
- }
-
- /**
- * Cancels a running download.
- */
- public void cancelDownload(final Context context, final String downloadUrl) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Cancelling download with url " + downloadUrl);
- Intent cancelIntent = new Intent(DownloadService.ACTION_CANCEL_DOWNLOAD);
- cancelIntent.putExtra(DownloadService.EXTRA_DOWNLOAD_URL, downloadUrl);
- context.sendBroadcast(cancelIntent);
- }
-
- /**
- * Cancels all running downloads
- */
- public void cancelAllDownloads(Context context) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Cancelling all running downloads");
- context.sendBroadcast(new Intent(
- DownloadService.ACTION_CANCEL_ALL_DOWNLOADS));
- }
-
- /**
- * Returns true if there is at least one Feed in the downloads queue.
- */
- public boolean isDownloadingFeeds() {
- for (DownloadRequest r : downloads.values()) {
- if (r.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks if feedfile is in the downloads list
- */
- public boolean isDownloadingFile(FeedFile item) {
- if (item.getDownload_url() != null) {
- return downloads.containsKey(item.getDownload_url());
- }
- return false;
- }
-
- public DownloadRequest getDownload(String downloadUrl) {
- return downloads.get(downloadUrl);
- }
-
- /**
- * Checks if feedfile with the given download url is in the downloads list
- */
- public boolean isDownloadingFile(String downloadUrl) {
- return downloads.get(downloadUrl) != null;
- }
-
- public boolean hasNoDownloads() {
- return downloads.isEmpty();
- }
-
- /**
- * Remove an object from the downloads-list of the requester.
- */
- public void removeDownload(DownloadRequest r) {
- if (downloads.remove(r.getSource()) == null) {
- Log.e(TAG,
- "Could not remove object with url " + r.getSource());
- }
- }
-
- /**
- * Get the number of uncompleted Downloads
- */
- public int getNumberOfDownloads() {
- return downloads.size();
- }
-
- public String getFeedfilePath(Context context)
- throws DownloadRequestException {
- return getExternalFilesDirOrThrowException(context, FEED_DOWNLOADPATH)
- .toString() + "/";
- }
-
- public String getFeedfileName(Feed feed) {
- String filename = feed.getDownload_url();
- if (feed.getTitle() != null && !feed.getTitle().isEmpty()) {
- filename = feed.getTitle();
- }
- return "feed-" + FileNameGenerator.generateFileName(filename);
- }
-
- public String getImagefilePath(Context context)
- throws DownloadRequestException {
- return getExternalFilesDirOrThrowException(context, IMAGE_DOWNLOADPATH)
- .toString() + "/";
- }
-
- public String getImagefileName(FeedImage image) {
- String filename = image.getDownload_url();
- if (image.getOwner() != null && image.getOwner().getHumanReadableIdentifier() != null) {
- filename = image.getOwner().getHumanReadableIdentifier();
- }
- return "image-" + FileNameGenerator.generateFileName(filename);
- }
-
- public String getMediafilePath(Context context, FeedMedia media)
- throws DownloadRequestException {
- File externalStorage = getExternalFilesDirOrThrowException(
- context,
- MEDIA_DOWNLOADPATH
- + FileNameGenerator.generateFileName(media.getItem()
- .getFeed().getTitle()) + "/"
- );
- return externalStorage.toString();
- }
-
- private File getExternalFilesDirOrThrowException(Context context,
- String type) throws DownloadRequestException {
- File result = UserPreferences.getDataFolder(context, type);
- if (result == null) {
- throw new DownloadRequestException(
- "Failed to access external storage");
- }
- return result;
- }
-
- public String getMediafilename(FeedMedia media) {
- String filename;
- String titleBaseFilename = "";
-
- // Try to generate the filename by the item title
- if (media.getItem() != null && media.getItem().getTitle() != null) {
- String title = media.getItem().getTitle();
- // Delete reserved characters
- titleBaseFilename = title.replaceAll("[\\\\/%\\?\\*:|<>\"\\p{Cntrl}]", "");
- titleBaseFilename = titleBaseFilename.trim();
- }
-
- String URLBaseFilename = URLUtil.guessFileName(media.getDownload_url(),
- null, media.getMime_type());
- ;
-
- if (titleBaseFilename != "") {
- // Append extension
- filename = titleBaseFilename + FilenameUtils.EXTENSION_SEPARATOR +
- FilenameUtils.getExtension(URLBaseFilename);
- } else {
- // Fall back on URL file name
- filename = URLBaseFilename;
- }
- return filename;
- }
-}
diff --git a/src/de/danoeh/antennapod/storage/FeedItemStatistics.java b/src/de/danoeh/antennapod/storage/FeedItemStatistics.java
deleted file mode 100644
index 8cb040756..000000000
--- a/src/de/danoeh/antennapod/storage/FeedItemStatistics.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package de.danoeh.antennapod.storage;
-
-import java.util.Date;
-
-/**
- * Contains information about a feed's items.
- */
-public class FeedItemStatistics {
- private long feedID;
- private int numberOfItems;
- private int numberOfNewItems;
- private int numberOfInProgressItems;
- private Date lastUpdate;
- private static final Date UNKNOWN_DATE = new Date(0);
-
-
- /**
- * Creates new FeedItemStatistics object.
- *
- * @param feedID ID of the feed.
- * @param numberOfItems Number of items that this feed has.
- * @param numberOfNewItems Number of unread items this feed has.
- * @param numberOfInProgressItems Number of items that the user has started listening to.
- * @param lastUpdate pubDate of the latest episode. A lastUpdate value of 0 will be interpreted as DATE_UNKOWN if
- * numberOfItems is 0.
- */
- public FeedItemStatistics(long feedID, int numberOfItems, int numberOfNewItems, int numberOfInProgressItems, Date lastUpdate) {
- this.feedID = feedID;
- this.numberOfItems = numberOfItems;
- this.numberOfNewItems = numberOfNewItems;
- this.numberOfInProgressItems = numberOfInProgressItems;
- if (numberOfItems > 0) {
- this.lastUpdate = (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
- } else {
- this.lastUpdate = UNKNOWN_DATE;
- }
- }
-
- public long getFeedID() {
- return feedID;
- }
-
- public int getNumberOfItems() {
- return numberOfItems;
- }
-
- public int getNumberOfNewItems() {
- return numberOfNewItems;
- }
-
- public int getNumberOfInProgressItems() {
- return numberOfInProgressItems;
- }
-
- /**
- * Returns the pubDate of the latest item in the feed. Users of this method
- * should check if this value is unkown or not by calling lastUpdateKnown() first.
- */
- public Date getLastUpdate() {
- return (lastUpdate != null) ? (Date) lastUpdate.clone() : null;
- }
-
- /**
- * Returns true if the lastUpdate value is known. The lastUpdate value is unkown if the
- * feed has no items.
- */
- public boolean lastUpdateKnown() {
- return lastUpdate != UNKNOWN_DATE;
- }
-}
diff --git a/src/de/danoeh/antennapod/storage/FeedSearcher.java b/src/de/danoeh/antennapod/storage/FeedSearcher.java
deleted file mode 100644
index e7aa93f83..000000000
--- a/src/de/danoeh/antennapod/storage/FeedSearcher.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package de.danoeh.antennapod.storage;
-
-import android.content.Context;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.feed.SearchResult;
-import de.danoeh.antennapod.util.comparator.SearchResultValueComparator;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
-/**
- * Performs search on Feeds and FeedItems
- */
-public class FeedSearcher {
- private static final String TAG = "FeedSearcher";
-
-
- /**
- * Performs a search in all feeds or one specific feed.
- */
- public static List<SearchResult> performSearch(final Context context,
- final String query, final long selectedFeed) {
- final int values[] = {0, 0, 1, 2};
- final String[] subtitles = {context.getString(R.string.found_in_shownotes_label),
- context.getString(R.string.found_in_shownotes_label),
- context.getString(R.string.found_in_chapters_label),
- context.getString(R.string.found_in_title_label)};
-
- List<SearchResult> result = new ArrayList<SearchResult>();
-
- FutureTask<List<FeedItem>>[] tasks = new FutureTask[4];
- (tasks[0] = DBTasks.searchFeedItemContentEncoded(context, selectedFeed, query)).run();
- (tasks[1] = DBTasks.searchFeedItemDescription(context, selectedFeed, query)).run();
- (tasks[2] = DBTasks.searchFeedItemChapters(context, selectedFeed, query)).run();
- (tasks[3] = DBTasks.searchFeedItemTitle(context, selectedFeed, query)).run();
- try {
- for (int i = 0; i < tasks.length; i++) {
- FutureTask task = tasks[i];
- List<FeedItem> items = (List<FeedItem>) task.get();
- for (FeedItem item : items) {
- result.add(new SearchResult(item, values[i], subtitles[i]));
- }
-
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- Collections.sort(result, new SearchResultValueComparator());
- return result;
- }
-}
diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
deleted file mode 100644
index 671ac30d5..000000000
--- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java
+++ /dev/null
@@ -1,1391 +0,0 @@
-package de.danoeh.antennapod.storage;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.MergeCursor;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteDatabase.CursorFactory;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
-
-import org.apache.commons.lang3.Validate;
-
-import java.util.Arrays;
-import java.util.List;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.feed.Chapter;
-import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.feed.FeedComponent;
-import de.danoeh.antennapod.feed.FeedImage;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.feed.FeedMedia;
-import de.danoeh.antennapod.feed.FeedPreferences;
-import de.danoeh.antennapod.service.download.DownloadStatus;
-import de.danoeh.antennapod.util.flattr.FlattrStatus;
-
-// TODO Remove media column from feeditem table
-
-/**
- * Implements methods for accessing the database
- */
-public class PodDBAdapter {
- private static final String TAG = "PodDBAdapter";
- private static final int DATABASE_VERSION = 12;
- public static final String DATABASE_NAME = "Antennapod.db";
-
- /**
- * Maximum number of arguments for IN-operator.
- */
- public static final int IN_OPERATOR_MAXIMUM = 800;
-
- /**
- * Maximum number of entries per search request.
- */
- 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;
- // ----------- 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";
- public static final String KEY_NAME = "name";
- public static final String KEY_LINK = "link";
- public static final String KEY_DESCRIPTION = "description";
- public static final String KEY_FILE_URL = "file_url";
- public static final String KEY_DOWNLOAD_URL = "download_url";
- public static final String KEY_PUBDATE = "pubDate";
- public static final String KEY_READ = "read";
- public static final String KEY_DURATION = "duration";
- public static final String KEY_POSITION = "position";
- public static final String KEY_SIZE = "filesize";
- public static final String KEY_MIME_TYPE = "mime_type";
- public static final String KEY_IMAGE = "image";
- public static final String KEY_FEED = "feed";
- public static final String KEY_MEDIA = "media";
- public static final String KEY_DOWNLOADED = "downloaded";
- public static final String KEY_LASTUPDATE = "last_update";
- public static final String KEY_FEEDFILE = "feedfile";
- public static final String KEY_REASON = "reason";
- public static final String KEY_SUCCESSFUL = "successful";
- public static final String KEY_FEEDFILETYPE = "feedfile_type";
- public static final String KEY_COMPLETION_DATE = "completion_date";
- public static final String KEY_FEEDITEM = "feeditem";
- public static final String KEY_CONTENT_ENCODED = "content_encoded";
- public static final String KEY_PAYMENT_LINK = "payment_link";
- public static final String KEY_START = "start";
- public static final String KEY_LANGUAGE = "language";
- public static final String KEY_AUTHOR = "author";
- public static final String KEY_HAS_CHAPTERS = "has_simple_chapters";
- public static final String KEY_TYPE = "type";
- public static final String KEY_ITEM_IDENTIFIER = "item_identifier";
- public static final String KEY_FLATTR_STATUS = "flattr_status";
- public static final String KEY_FEED_IDENTIFIER = "feed_identifier";
- public static final String KEY_REASON_DETAILED = "reason_detailed";
- public static final String KEY_DOWNLOADSTATUS_TITLE = "title";
- public static final String KEY_CHAPTER_TYPE = "type";
- public static final String KEY_PLAYBACK_COMPLETION_DATE = "playback_completion_date";
- public static final String KEY_AUTO_DOWNLOAD = "auto_download";
- public static final String KEY_PLAYED_DURATION = "played_duration";
- public static final String KEY_USERNAME = "username";
- public static final String KEY_PASSWORD = "password";
-
- // Table names
- public static final String TABLE_NAME_FEEDS = "Feeds";
- public static final String TABLE_NAME_FEED_ITEMS = "FeedItems";
- public static final String TABLE_NAME_FEED_IMAGES = "FeedImages";
- public static final String TABLE_NAME_FEED_MEDIA = "FeedMedia";
- public static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog";
- public static final String TABLE_NAME_QUEUE = "Queue";
- public static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters";
-
- // SQL Statements for creating new tables
- private static final String TABLE_PRIMARY_KEY = KEY_ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT ,";
-
- private static final String CREATE_TABLE_FEEDS = "CREATE TABLE "
- + TABLE_NAME_FEEDS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
- + " TEXT," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL + " TEXT,"
- + KEY_DOWNLOADED + " INTEGER," + KEY_LINK + " TEXT,"
- + KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
- + KEY_LASTUPDATE + " TEXT," + KEY_LANGUAGE + " TEXT," + KEY_AUTHOR
- + " TEXT," + KEY_IMAGE + " INTEGER," + KEY_TYPE + " TEXT,"
- + KEY_FEED_IDENTIFIER + " TEXT," + KEY_AUTO_DOWNLOAD + " INTEGER DEFAULT 1,"
- + KEY_FLATTR_STATUS + " INTEGER,"
- + KEY_USERNAME + " TEXT,"
- + KEY_PASSWORD + " TEXT)";
-
- private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
- + TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
- + " TEXT," + KEY_CONTENT_ENCODED + " TEXT," + KEY_PUBDATE
- + " INTEGER," + KEY_READ + " INTEGER," + KEY_LINK + " TEXT,"
- + KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT,"
- + KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER,"
- + KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT,"
- + KEY_FLATTR_STATUS + " INTEGER,"
- + KEY_IMAGE + " INTEGER)";
-
- private static final String CREATE_TABLE_FEED_IMAGES = "CREATE TABLE "
- + TABLE_NAME_FEED_IMAGES + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
- + " TEXT," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL + " TEXT,"
- + KEY_DOWNLOADED + " INTEGER)";
-
- private static final String CREATE_TABLE_FEED_MEDIA = "CREATE TABLE "
- + TABLE_NAME_FEED_MEDIA + " (" + TABLE_PRIMARY_KEY + KEY_DURATION
- + " INTEGER," + KEY_FILE_URL + " TEXT," + KEY_DOWNLOAD_URL
- + " TEXT," + KEY_DOWNLOADED + " INTEGER," + KEY_POSITION
- + " INTEGER," + KEY_SIZE + " INTEGER," + KEY_MIME_TYPE + " TEXT,"
- + KEY_PLAYBACK_COMPLETION_DATE + " INTEGER,"
- + KEY_FEEDITEM + " INTEGER,"
- + KEY_PLAYED_DURATION + " INTEGER)";
-
- private static final String CREATE_TABLE_DOWNLOAD_LOG = "CREATE TABLE "
- + TABLE_NAME_DOWNLOAD_LOG + " (" + TABLE_PRIMARY_KEY + KEY_FEEDFILE
- + " INTEGER," + KEY_FEEDFILETYPE + " INTEGER," + KEY_REASON
- + " INTEGER," + KEY_SUCCESSFUL + " INTEGER," + KEY_COMPLETION_DATE
- + " INTEGER," + KEY_REASON_DETAILED + " TEXT,"
- + KEY_DOWNLOADSTATUS_TITLE + " TEXT)";
-
- private static final String CREATE_TABLE_QUEUE = "CREATE TABLE "
- + TABLE_NAME_QUEUE + "(" + KEY_ID + " INTEGER PRIMARY KEY,"
- + KEY_FEEDITEM + " INTEGER," + KEY_FEED + " INTEGER)";
-
- private static final String CREATE_TABLE_SIMPLECHAPTERS = "CREATE TABLE "
- + TABLE_NAME_SIMPLECHAPTERS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
- + " TEXT," + KEY_START + " INTEGER," + KEY_FEEDITEM + " INTEGER,"
- + KEY_LINK + " TEXT," + KEY_CHAPTER_TYPE + " INTEGER)";
-
- private SQLiteDatabase db;
- private final Context context;
- private PodDBHelper helper;
-
- /**
- * Select all columns from the feed-table
- */
- private static final String[] FEED_SEL_STD = {
- TABLE_NAME_FEEDS + "." + KEY_ID,
- TABLE_NAME_FEEDS + "." + KEY_TITLE,
- TABLE_NAME_FEEDS + "." + KEY_FILE_URL,
- TABLE_NAME_FEEDS + "." + KEY_DOWNLOAD_URL,
- TABLE_NAME_FEEDS + "." + KEY_DOWNLOADED,
- TABLE_NAME_FEEDS + "." + KEY_LINK,
- TABLE_NAME_FEEDS + "." + KEY_DESCRIPTION,
- TABLE_NAME_FEEDS + "." + KEY_PAYMENT_LINK,
- TABLE_NAME_FEEDS + "." + KEY_LASTUPDATE,
- TABLE_NAME_FEEDS + "." + KEY_LANGUAGE,
- TABLE_NAME_FEEDS + "." + KEY_AUTHOR,
- TABLE_NAME_FEEDS + "." + KEY_IMAGE,
- TABLE_NAME_FEEDS + "." + KEY_TYPE,
- TABLE_NAME_FEEDS + "." + KEY_FEED_IDENTIFIER,
- TABLE_NAME_FEEDS + "." + KEY_AUTO_DOWNLOAD,
- TABLE_NAME_FEEDS + "." + KEY_FLATTR_STATUS,
- TABLE_NAME_FEEDS + "." + KEY_USERNAME,
- TABLE_NAME_FEEDS + "." + KEY_PASSWORD
- };
-
- // 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_PREFERENCES_USERNAME = 16;
- public static final int IDX_FEED_SEL_PREFERENCES_PASSWORD = 17;
-
-
- /**
- * Select all columns from the feeditems-table except description and
- * content-encoded.
- */
- private static final String[] FEEDITEM_SEL_FI_SMALL = {
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID,
- TABLE_NAME_FEED_ITEMS + "." + KEY_TITLE,
- 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_FEED,
- TABLE_NAME_FEED_ITEMS + "." + KEY_HAS_CHAPTERS,
- TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER,
- TABLE_NAME_FEED_ITEMS + "." + KEY_FLATTR_STATUS,
- TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE};
-
- /**
- * Contains FEEDITEM_SEL_FI_SMALL as comma-separated list. Useful for raw queries.
- */
- private static final String SEL_FI_SMALL_STR;
-
- static {
- String selFiSmall = Arrays.toString(FEEDITEM_SEL_FI_SMALL);
- 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;
-
- static PodDBHelper dbHelperSingleton;
-
- private static synchronized PodDBHelper getDbHelperSingleton(Context appContext) {
- if (dbHelperSingleton == null) {
- dbHelperSingleton = new PodDBHelper(appContext, DATABASE_NAME, null, DATABASE_VERSION);
- }
- return dbHelperSingleton;
- }
-
- public PodDBAdapter(Context c) {
- this.context = c;
- helper = getDbHelperSingleton(c.getApplicationContext());
- }
-
- public PodDBAdapter open() {
- if (db == null || !db.isOpen() || db.isReadOnly()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Opening DB");
- try {
- db = helper.getWritableDatabase();
- } catch (SQLException ex) {
- ex.printStackTrace();
- db = helper.getReadableDatabase();
- }
- }
- return this;
- }
-
- public void close() {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Closing DB");
- //db.close();
- }
-
- public static boolean deleteDatabase(Context context) {
- Log.w(TAG, "Deleting database");
- dbHelperSingleton.close();
- dbHelperSingleton = null;
- return context.deleteDatabase(DATABASE_NAME);
- }
-
- /**
- * Inserts or updates a feed entry
- *
- * @return the id of the entry
- */
- public long setFeed(Feed feed) {
- ContentValues values = new ContentValues();
- values.put(KEY_TITLE, feed.getTitle());
- values.put(KEY_LINK, feed.getLink());
- values.put(KEY_DESCRIPTION, feed.getDescription());
- values.put(KEY_PAYMENT_LINK, feed.getPaymentLink());
- values.put(KEY_AUTHOR, feed.getAuthor());
- values.put(KEY_LANGUAGE, feed.getLanguage());
- if (feed.getImage() != null) {
- if (feed.getImage().getId() == 0) {
- setImage(feed.getImage());
- }
- values.put(KEY_IMAGE, feed.getImage().getId());
- }
-
- values.put(KEY_FILE_URL, feed.getFile_url());
- values.put(KEY_DOWNLOAD_URL, feed.getDownload_url());
- values.put(KEY_DOWNLOADED, feed.isDownloaded());
- values.put(KEY_LASTUPDATE, feed.getLastUpdate().getTime());
- values.put(KEY_TYPE, feed.getType());
- values.put(KEY_FEED_IDENTIFIER, feed.getFeedIdentifier());
-
- Log.d(TAG, "Setting feed with flattr status " + feed.getTitle() + ": " + feed.getFlattrStatus().toLong());
-
- values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong());
- if (feed.getId() == 0) {
- // Create new entry
- if (BuildConfig.DEBUG)
- Log.d(this.toString(), "Inserting new Feed into db");
- feed.setId(db.insert(TABLE_NAME_FEEDS, null, values));
- } else {
- if (BuildConfig.DEBUG)
- Log.d(this.toString(), "Updating existing Feed in db");
- db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?",
- new String[]{String.valueOf(feed.getId())});
-
- }
- return feed.getId();
- }
-
- public void setFeedPreferences(FeedPreferences prefs) {
- if (prefs.getFeedID() == 0) {
- throw new IllegalArgumentException("Feed ID of preference must not be null");
- }
- ContentValues values = new ContentValues();
- values.put(KEY_AUTO_DOWNLOAD, prefs.getAutoDownload());
- values.put(KEY_USERNAME, prefs.getUsername());
- values.put(KEY_PASSWORD, prefs.getPassword());
- db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(prefs.getFeedID())});
- }
-
- /**
- * Inserts or updates an image entry
- *
- * @return the id of the entry
- */
- public long setImage(FeedImage image) {
- db.beginTransaction();
- ContentValues values = new ContentValues();
- values.put(KEY_TITLE, image.getTitle());
- values.put(KEY_DOWNLOAD_URL, image.getDownload_url());
- values.put(KEY_DOWNLOADED, image.isDownloaded());
- values.put(KEY_FILE_URL, image.getFile_url());
- if (image.getId() == 0) {
- image.setId(db.insert(TABLE_NAME_FEED_IMAGES, null, values));
- } else {
- db.update(TABLE_NAME_FEED_IMAGES, values, KEY_ID + "=?",
- new String[]{String.valueOf(image.getId())});
- }
-
- final FeedComponent owner = image.getOwner();
- if (owner != null && owner.getId() != 0) {
- values.clear();
- values.put(KEY_IMAGE, image.getId());
- if (owner instanceof Feed) {
- db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(image.getOwner().getId())});
- }
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- return image.getId();
- }
-
- /**
- * Inserts or updates an image entry
- *
- * @return the id of the entry
- */
- public long setMedia(FeedMedia media) {
- ContentValues values = new ContentValues();
- values.put(KEY_DURATION, media.getDuration());
- values.put(KEY_POSITION, media.getPosition());
- values.put(KEY_SIZE, media.getSize());
- values.put(KEY_MIME_TYPE, media.getMime_type());
- values.put(KEY_DOWNLOAD_URL, media.getDownload_url());
- values.put(KEY_DOWNLOADED, media.isDownloaded());
- values.put(KEY_FILE_URL, media.getFile_url());
-
- if (media.getPlaybackCompletionDate() != null) {
- values.put(KEY_PLAYBACK_COMPLETION_DATE, media
- .getPlaybackCompletionDate().getTime());
- } else {
- values.put(KEY_PLAYBACK_COMPLETION_DATE, 0);
- }
- if (media.getItem() != null) {
- values.put(KEY_FEEDITEM, media.getItem().getId());
- }
- if (media.getId() == 0) {
- media.setId(db.insert(TABLE_NAME_FEED_MEDIA, null, values));
- } else {
- db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
- new String[]{String.valueOf(media.getId())});
- }
- return media.getId();
- }
-
- public void setFeedMediaPlaybackInformation(FeedMedia media) {
- if (media.getId() != 0) {
- ContentValues values = new ContentValues();
- values.put(KEY_POSITION, media.getPosition());
- values.put(KEY_DURATION, media.getDuration());
- values.put(KEY_PLAYED_DURATION, media.getPlayedDuration());
- db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
- new String[]{String.valueOf(media.getId())});
- } else {
- Log.e(TAG, "setFeedMediaPlaybackInformation: ID of media was 0");
- }
- }
-
- public void setFeedMediaPlaybackCompletionDate(FeedMedia media) {
- if (media.getId() != 0) {
- ContentValues values = new ContentValues();
- values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate().getTime());
- values.put(KEY_PLAYED_DURATION, media.getPlayedDuration());
- db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
- new String[]{String.valueOf(media.getId())});
- } else {
- Log.e(TAG, "setFeedMediaPlaybackCompletionDate: ID of media was 0");
- }
- }
-
- /**
- * Insert all FeedItems of a feed and the feed object itself in a single
- * transaction
- */
- public void setCompleteFeed(Feed... feeds) {
- db.beginTransaction();
- for (Feed feed : feeds) {
- setFeed(feed);
- if (feed.getItems() != null) {
- for (FeedItem item : feed.getItems()) {
- setFeedItem(item, false);
- }
- }
- if (feed.getPreferences() != null) {
- setFeedPreferences(feed.getPreferences());
- }
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- /**
- * Update the flattr status of a feed
- */
- public void setFeedFlattrStatus(Feed feed) {
- ContentValues values = new ContentValues();
- values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong());
- db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feed.getId())});
- }
-
- /**
- * Get all feeds in the flattr queue.
- */
- public Cursor getFeedsInFlattrQueueCursor() {
- return db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_FLATTR_STATUS + "=?",
- new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)}, null, null, null);
- }
-
- /**
- * Get all feed items in the flattr queue.
- */
- public Cursor getFeedItemsInFlattrQueueCursor() {
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FLATTR_STATUS + "=?",
- new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)}, null, null, null);
- }
-
- /**
- * Counts feeds and feed items in the flattr queue
- */
- public int getFlattrQueueSize() {
- int res = 0;
- Cursor c = db.rawQuery(String.format("SELECT count(*) FROM %s WHERE %s=%s",
- TABLE_NAME_FEEDS, KEY_FLATTR_STATUS, String.valueOf(FlattrStatus.STATUS_QUEUE)), null);
- if (c.moveToFirst()) {
- res = c.getInt(0);
- c.close();
- } else {
- Log.e(TAG, "Unable to determine size of flattr queue: Could not count number of feeds");
- }
- c = db.rawQuery(String.format("SELECT count(*) FROM %s WHERE %s=%s",
- TABLE_NAME_FEED_ITEMS, KEY_FLATTR_STATUS, String.valueOf(FlattrStatus.STATUS_QUEUE)), null);
- if (c.moveToFirst()) {
- res += c.getInt(0);
- c.close();
- } else {
- Log.e(TAG, "Unable to determine size of flattr queue: Could not count number of feed items");
- }
-
- return res;
- }
-
- /**
- * Updates the download URL of a Feed.
- */
- public void setFeedDownloadUrl(String original, String updated) {
- ContentValues values = new ContentValues();
- values.put(KEY_DOWNLOAD_URL, updated);
- db.update(TABLE_NAME_FEEDS, values, KEY_DOWNLOAD_URL + "=?", new String[]{original});
- }
-
- public void setFeedItemlist(List<FeedItem> items) {
- db.beginTransaction();
- for (FeedItem item : items) {
- setFeedItem(item, true);
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public long setSingleFeedItem(FeedItem item) {
- db.beginTransaction();
- long result = setFeedItem(item, true);
- db.setTransactionSuccessful();
- db.endTransaction();
- return result;
- }
-
- /**
- * Update the flattr status of a FeedItem
- */
- public void setFeedItemFlattrStatus(FeedItem feedItem) {
- ContentValues values = new ContentValues();
- values.put(KEY_FLATTR_STATUS, feedItem.getFlattrStatus().toLong());
- db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(feedItem.getId())});
- }
-
- /**
- * Update the flattr status of a feed or feed item specified by its payment link
- * and the new flattr status to use
- */
- public void setItemFlattrStatus(String url, FlattrStatus status) {
- //Log.d(TAG, "setItemFlattrStatus(" + url + ") = " + status.toString());
- ContentValues values = new ContentValues();
- values.put(KEY_FLATTR_STATUS, status.toLong());
-
- // regexps in sqlite would be neat!
- String[] query_urls = new String[]{
- "*" + url + "&*",
- "*" + url + "%2F&*",
- "*" + url + "",
- "*" + url + "%2F"
- };
-
- if (db.update(TABLE_NAME_FEEDS, values,
- KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls
- ) > 0) {
- Log.i(TAG, "setItemFlattrStatus found match for " + url + " = " + status.toLong() + " in Feeds table");
- return;
- }
- if (db.update(TABLE_NAME_FEED_ITEMS, values,
- KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?"
- + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls
- ) > 0) {
- Log.i(TAG, "setItemFlattrStatus found match for " + url + " = " + status.toLong() + " in FeedsItems table");
- }
- }
-
- /**
- * Reset flattr status to unflattrd for all items
- */
- public void clearAllFlattrStatus() {
- ContentValues values = new ContentValues();
- values.put(KEY_FLATTR_STATUS, 0);
- db.update(TABLE_NAME_FEEDS, values, null, null);
- db.update(TABLE_NAME_FEED_ITEMS, values, null, null);
- }
-
- /**
- * Inserts or updates a feeditem entry
- *
- * @param item The FeedItem
- * @param saveFeed true if the Feed of the item should also be saved. This should be set to
- * false if the method is executed on a list of FeedItems of the same Feed.
- * @return the id of the entry
- */
- private long setFeedItem(FeedItem item, boolean saveFeed) {
- ContentValues values = new ContentValues();
- values.put(KEY_TITLE, item.getTitle());
- values.put(KEY_LINK, item.getLink());
- if (item.getDescription() != null) {
- values.put(KEY_DESCRIPTION, item.getDescription());
- }
- if (item.getContentEncoded() != null) {
- values.put(KEY_CONTENT_ENCODED, item.getContentEncoded());
- }
- values.put(KEY_PUBDATE, item.getPubDate().getTime());
- values.put(KEY_PAYMENT_LINK, item.getPaymentLink());
- if (saveFeed && item.getFeed() != null) {
- setFeed(item.getFeed());
- }
- values.put(KEY_FEED, item.getFeed().getId());
- values.put(KEY_READ, item.isRead());
- values.put(KEY_HAS_CHAPTERS, item.getChapters() != null);
- values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier());
- values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong());
- if (item.hasItemImage()) {
- if (item.getImage().getId() == 0) {
- setImage(item.getImage());
- }
- values.put(KEY_IMAGE, item.getImage().getId());
- }
-
- if (item.getId() == 0) {
- item.setId(db.insert(TABLE_NAME_FEED_ITEMS, null, values));
- } else {
- db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?",
- new String[]{String.valueOf(item.getId())});
- }
- if (item.getMedia() != null) {
- setMedia(item.getMedia());
- }
- if (item.getChapters() != null) {
- setChapters(item);
- }
- return item.getId();
- }
-
- public void setFeedItemRead(boolean read, long itemId, long mediaId,
- boolean resetMediaPosition) {
- db.beginTransaction();
- ContentValues values = new ContentValues();
-
- values.put(KEY_READ, read);
- db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(itemId)});
-
- if (resetMediaPosition) {
- values.clear();
- values.put(KEY_POSITION, 0);
- db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?", new String[]{String.valueOf(mediaId)});
- }
-
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public void setFeedItemRead(boolean read, long... itemIds) {
- db.beginTransaction();
- ContentValues values = new ContentValues();
- for (long id : itemIds) {
- values.clear();
- values.put(KEY_READ, read);
- db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", new String[]{String.valueOf(id)});
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public void setChapters(FeedItem item) {
- ContentValues values = new ContentValues();
- for (Chapter chapter : item.getChapters()) {
- values.put(KEY_TITLE, chapter.getTitle());
- values.put(KEY_START, chapter.getStart());
- values.put(KEY_FEEDITEM, item.getId());
- 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));
- } else {
- db.update(TABLE_NAME_SIMPLECHAPTERS, values, KEY_ID + "=?",
- new String[]{String.valueOf(chapter.getId())});
- }
- }
- }
-
- /**
- * Inserts or updates a download status.
- */
- public long setDownloadStatus(DownloadStatus status) {
- ContentValues values = new ContentValues();
- values.put(KEY_FEEDFILE, status.getFeedfileId());
- values.put(KEY_FEEDFILETYPE, status.getFeedfileType());
- values.put(KEY_REASON, status.getReason().getCode());
- values.put(KEY_SUCCESSFUL, status.isSuccessful());
- values.put(KEY_COMPLETION_DATE, status.getCompletionDate().getTime());
- values.put(KEY_REASON_DETAILED, status.getReasonDetailed());
- values.put(KEY_DOWNLOADSTATUS_TITLE, status.getTitle());
- if (status.getId() == 0) {
- status.setId(db.insert(TABLE_NAME_DOWNLOAD_LOG, null, values));
- } else {
- db.update(TABLE_NAME_DOWNLOAD_LOG, values, KEY_ID + "=?",
- new String[]{String.valueOf(status.getId())});
- }
- return status.getId();
- }
-
- public long getDownloadLogSize() {
- final String query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_DOWNLOAD_LOG);
- Cursor result = db.rawQuery(query, null);
- long count = 0;
- if (result.moveToFirst()) {
- count = result.getLong(0);
- }
- result.close();
- 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<FeedItem> queue) {
- ContentValues values = new ContentValues();
- db.beginTransaction();
- db.delete(TABLE_NAME_QUEUE, null, null);
- for (int i = 0; i < queue.size(); i++) {
- FeedItem item = queue.get(i);
- values.put(KEY_ID, i);
- values.put(KEY_FEEDITEM, item.getId());
- values.put(KEY_FEED, item.getFeed().getId());
- db.insertWithOnConflict(TABLE_NAME_QUEUE, null, values,
- SQLiteDatabase.CONFLICT_REPLACE);
- }
- db.setTransactionSuccessful();
- db.endTransaction();
- }
-
- public void clearQueue() {
- db.delete(TABLE_NAME_QUEUE, null, null);
- }
-
- public void removeFeedMedia(FeedMedia media) {
- db.delete(TABLE_NAME_FEED_MEDIA, KEY_ID + "=?",
- new String[]{String.valueOf(media.getId())});
- }
-
- public void removeChaptersOfItem(FeedItem item) {
- db.delete(TABLE_NAME_SIMPLECHAPTERS, KEY_FEEDITEM + "=?",
- new String[]{String.valueOf(item.getId())});
- }
-
- public void removeFeedImage(FeedImage image) {
- db.delete(TABLE_NAME_FEED_IMAGES, KEY_ID + "=?",
- new String[]{String.valueOf(image.getId())});
- }
-
- /**
- * Remove a FeedItem and its FeedMedia entry.
- */
- public void removeFeedItem(FeedItem item) {
- if (item.getMedia() != null) {
- removeFeedMedia(item.getMedia());
- }
- if (item.getChapters() != null) {
- removeChaptersOfItem(item);
- }
- if (item.hasItemImage()) {
- removeFeedImage(item.getImage());
- }
- db.delete(TABLE_NAME_FEED_ITEMS, KEY_ID + "=?",
- new String[]{String.valueOf(item.getId())});
- }
-
- /**
- * Remove a feed with all its FeedItems and Media entries.
- */
- public void removeFeed(Feed feed) {
- db.beginTransaction();
- if (feed.getImage() != null) {
- removeFeedImage(feed.getImage());
- }
- if (feed.getItems() != null) {
- for (FeedItem item : feed.getItems()) {
- removeFeedItem(item);
- }
- }
-
- db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?",
- new String[]{String.valueOf(feed.getId())});
- db.setTransactionSuccessful();
- 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);
- db.update(TABLE_NAME_FEED_MEDIA, values, null, null);
- }
-
- /**
- * Get all Feeds from the Feed Table.
- *
- * @return The cursor of the query
- */
- public final Cursor getAllFeedsCursor() {
- Cursor c = db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, null, null, null, null,
- KEY_TITLE + " COLLATE NOCASE ASC");
- return c;
- }
-
- public final Cursor getFeedCursorDownloadUrls() {
- return db.query(TABLE_NAME_FEEDS, new String[]{KEY_ID, KEY_DOWNLOAD_URL}, null, null, null, null, null);
- }
-
- public final Cursor getExpiredFeedsCursor(long expirationTime) {
- Cursor c = db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_LASTUPDATE + " < " + String.valueOf(System.currentTimeMillis() - expirationTime),
- null, null, null,
- null);
- return c;
- }
-
- /**
- * Returns a cursor with all FeedItems of a Feed. Uses FEEDITEM_SEL_FI_SMALL
- *
- * @param feed The feed you want to get the FeedItems from.
- * @return The cursor of the query
- */
- public final Cursor getAllItemsOfFeedCursor(final Feed feed) {
- return getAllItemsOfFeedCursor(feed.getId());
- }
-
- public final Cursor getAllItemsOfFeedCursor(final long feedId) {
- Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=?", new String[]{String.valueOf(feedId)}, null, null,
- null
- );
- return c;
- }
-
- /**
- * Return a cursor with the SEL_FI_EXTRA selection of a single feeditem.
- */
- public final Cursor getExtraInformationOfItem(final FeedItem item) {
- Cursor c = db
- .query(TABLE_NAME_FEED_ITEMS, SEL_FI_EXTRA, KEY_ID + "=?",
- new String[]{String.valueOf(item.getId())}, null,
- null, null);
- return c;
- }
-
- /**
- * Returns a cursor for a DB query in the FeedMedia table for a given ID.
- *
- * @param item The item you want to get the FeedMedia from
- * @return The cursor of the query
- */
- public final Cursor getFeedMediaOfItemCursor(final FeedItem item) {
- Cursor c = db.query(TABLE_NAME_FEED_MEDIA, null, KEY_ID + "=?",
- new String[]{String.valueOf(item.getMedia().getId())}, null,
- null, null);
- return c;
- }
-
- /**
- * Returns a cursor for a DB query in the FeedImages table for a given ID.
- *
- * @param id ID of the FeedImage
- * @return The cursor of the query
- */
- public final Cursor getImageCursor(final long id) {
- Cursor c = db.query(TABLE_NAME_FEED_IMAGES, null, KEY_ID + "=?",
- new String[]{String.valueOf(id)}, null, null, null);
- return c;
- }
-
- public final Cursor getSimpleChaptersOfFeedItemCursor(final FeedItem item) {
- Cursor c = db.query(TABLE_NAME_SIMPLECHAPTERS, null, KEY_FEEDITEM
- + "=?", new String[]{String.valueOf(item.getId())}, null,
- null, null
- );
- return c;
- }
-
- public final Cursor getDownloadLogCursor(final int limit) {
- Cursor c = db.query(TABLE_NAME_DOWNLOAD_LOG, null, null, null, null,
- null, KEY_COMPLETION_DATE + " DESC LIMIT " + limit);
- return c;
- }
-
- /**
- * Returns a cursor which contains all feed items in the queue. The returned
- * 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,
- 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);
- 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;
- }
-
- public Cursor getQueueIDCursor() {
- Cursor c = db.query(TABLE_NAME_QUEUE, new String[]{KEY_FEEDITEM}, null, null, null, null, KEY_ID + " ASC", null);
- return c;
- }
-
- /**
- * Returns a cursor which contains all feed items in the unread items list.
- * The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection.
- */
- public final Cursor getUnreadItemsCursor() {
- Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_READ
- + "=0", null, null, null, KEY_PUBDATE + " DESC");
- return c;
- }
-
- public final Cursor getUnreadItemIdsCursor() {
- Cursor c = db.query(TABLE_NAME_FEED_ITEMS, new String[]{KEY_ID},
- KEY_READ + "=0", null, null, null, KEY_PUBDATE + " DESC");
- return c;
-
- }
-
- public final Cursor getRecentlyPublishedItemsCursor(int limit) {
- Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, null, null, null, null, KEY_PUBDATE + " DESC LIMIT " + limit);
- return c;
- }
-
- public Cursor getDownloadedItemsCursor() {
- final String query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS
- + " INNER JOIN " + TABLE_NAME_FEED_MEDIA + " ON "
- + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "="
- + TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM + " WHERE "
- + TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + ">0";
- Cursor c = db.rawQuery(query, null);
- return c;
- }
-
- /**
- * Returns a cursor which contains feed media objects with a playback
- * completion date in ascending order.
- *
- * @param limit The maximum row count of the returned cursor. Must be an
- * integer >= 0.
- * @throws IllegalArgumentException if limit < 0
- */
- public final Cursor getCompletedMediaCursor(int limit) {
- Validate.isTrue(limit >= 0, "Limit must be >= 0");
-
- Cursor c = db.query(TABLE_NAME_FEED_MEDIA, null,
- KEY_PLAYBACK_COMPLETION_DATE + " > 0 LIMIT " + limit, null, null,
- null, null);
- return c;
- }
-
- public final Cursor getSingleFeedMediaCursor(long id) {
- return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_ID + "=?", new String[]{String.valueOf(id)}, null, null, null);
- }
-
- public final Cursor getFeedMediaCursorByItemID(String... mediaIds) {
- int length = mediaIds.length;
- if (length > IN_OPERATOR_MAXIMUM) {
- Log.w(TAG, "Length of id array is larger than "
- + IN_OPERATOR_MAXIMUM + ". Creating multiple cursors");
- int numCursors = (int) (((double) length) / (IN_OPERATOR_MAXIMUM)) + 1;
- Cursor[] cursors = new Cursor[numCursors];
- for (int i = 0; i < numCursors; i++) {
- int neededLength = 0;
- String[] parts = null;
- final int elementsLeft = length - i * IN_OPERATOR_MAXIMUM;
-
- if (elementsLeft >= IN_OPERATOR_MAXIMUM) {
- neededLength = IN_OPERATOR_MAXIMUM;
- parts = Arrays.copyOfRange(mediaIds, i
- * IN_OPERATOR_MAXIMUM, (i + 1)
- * IN_OPERATOR_MAXIMUM);
- } else {
- neededLength = elementsLeft;
- parts = Arrays.copyOfRange(mediaIds, i
- * IN_OPERATOR_MAXIMUM, (i * IN_OPERATOR_MAXIMUM)
- + neededLength);
- }
-
- cursors[i] = db.rawQuery("SELECT * FROM "
- + TABLE_NAME_FEED_MEDIA + " WHERE " + KEY_FEEDITEM + " IN "
- + buildInOperator(neededLength), parts);
- }
- return new MergeCursor(cursors);
- } else {
- return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_FEEDITEM + " IN "
- + buildInOperator(length), mediaIds, null, null, null);
- }
- }
-
- /**
- * Builds an IN-operator argument depending on the number of items.
- */
- private String buildInOperator(int size) {
- if (size == 1) {
- return "(?)";
- }
- StringBuffer buffer = new StringBuffer("(");
- for (int i = 0; i < size - 1; i++) {
- buffer.append("?,");
- }
- buffer.append("?)");
- return buffer.toString();
- }
-
- public final Cursor getFeedCursor(final long id) {
- Cursor c = db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_ID + "=" + id, null,
- null, null, null);
- return c;
- }
-
- public final Cursor getFeedItemCursor(final String... ids) {
- if (ids.length > IN_OPERATOR_MAXIMUM) {
- throw new IllegalArgumentException(
- "number of IDs must not be larger than "
- + IN_OPERATOR_MAXIMUM
- );
- }
-
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_ID + " IN "
- + buildInOperator(ids.length), ids, null, null, null);
-
- }
-
- public int getQueueSize() {
- final String query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_QUEUE);
- Cursor c = db.rawQuery(query, null);
- int result = 0;
- if (c.moveToFirst()) {
- result = c.getInt(0);
- }
- c.close();
- return result;
- }
-
- public final int getNumberOfUnreadItems() {
- final String query = "SELECT COUNT(DISTINCT " + KEY_ID + ") AS count FROM " + TABLE_NAME_FEED_ITEMS +
- " WHERE " + KEY_READ + " = 0";
- Cursor c = db.rawQuery(query, null);
- int result = 0;
- if (c.moveToFirst()) {
- result = c.getInt(0);
- }
- c.close();
- return result;
- }
-
- public final int getNumberOfDownloadedEpisodes() {
- final String query = "SELECT COUNT(DISTINCT " + KEY_ID + ") AS count FROM " + TABLE_NAME_FEED_MEDIA +
- " WHERE " + KEY_DOWNLOADED + " > 0";
-
- Cursor c = db.rawQuery(query, null);
- int result = 0;
- if (c.moveToFirst()) {
- result = c.getInt(0);
- }
- c.close();
- return result;
- }
-
- /**
- * Uses DatabaseUtils to escape a search query and removes ' at the
- * beginning and the end of the string returned by the escape method.
- */
- private String prepareSearchQuery(String query) {
- StringBuilder builder = new StringBuilder();
- DatabaseUtils.appendEscapedSQLString(builder, query);
- builder.deleteCharAt(0);
- builder.deleteCharAt(builder.length() - 1);
- return builder.toString();
- }
-
- /**
- * Searches for the given query in the description of all items or the items
- * of a specified feed.
- *
- * @return A cursor with all search results in SEL_FI_EXTRA selection.
- */
- public Cursor searchItemDescriptions(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_DESCRIPTION + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
- } else {
- // search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_DESCRIPTION + " LIKE '%" + prepareSearchQuery(query)
- + "%'", null, null, null, null
- );
- }
- }
-
- /**
- * Searches for the given query in the content-encoded field of all items or
- * the items of a specified feed.
- *
- * @return A cursor with all search results in SEL_FI_EXTRA selection.
- */
- public Cursor searchItemContentEncoded(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_CONTENT_ENCODED + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
- } else {
- // search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_CONTENT_ENCODED + " LIKE '%"
- + prepareSearchQuery(query) + "%'", null, null,
- null, null
- );
- }
- }
-
- public Cursor searchItemTitles(long feedID, String query) {
- if (feedID != 0) {
- // search items in specific feed
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED
- + "=? AND " + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(query) + "%'",
- new String[]{String.valueOf(feedID)}, null, null,
- null
- );
- } else {
- // search through all items
- return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL,
- KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(query) + "%'", null, null,
- null, null
- );
- }
- }
-
- public Cursor searchItemChapters(long feedID, String searchQuery) {
- final String query;
- if (feedID != 0) {
- query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS + " INNER JOIN " +
- TABLE_NAME_SIMPLECHAPTERS + " ON " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_FEEDITEM + "=" +
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" +
- feedID + " AND " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(searchQuery) + "%'";
- } else {
- query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS + " INNER JOIN " +
- TABLE_NAME_SIMPLECHAPTERS + " ON " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_FEEDITEM + "=" +
- TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " WHERE " + TABLE_NAME_SIMPLECHAPTERS + "." + KEY_TITLE + " LIKE '%"
- + prepareSearchQuery(searchQuery) + "%'";
- }
- return db.rawQuery(query, null);
- }
-
-
- public static final int IDX_FEEDSTATISTICS_FEED = 0;
- public static final int IDX_FEEDSTATISTICS_NUM_ITEMS = 1;
- public static final int IDX_FEEDSTATISTICS_NEW_ITEMS = 2;
- public static final int IDX_FEEDSTATISTICS_LATEST_EPISODE = 3;
- public static final int IDX_FEEDSTATISTICS_IN_PROGRESS_EPISODES = 4;
-
- /**
- * Select number of items, new items, the date of the latest episode and the number of episodes in progress. The result
- * is sorted by the title of the feed.
- */
- private static final String FEED_STATISTICS_QUERY = "SELECT Feeds.id, num_items, new_items, latest_episode, in_progress FROM " +
- " Feeds LEFT JOIN " +
- "(SELECT feed,count(*) AS num_items," +
- " COUNT(CASE WHEN read=0 THEN 1 END) AS new_items," +
- " MAX(pubDate) AS latest_episode," +
- " COUNT(CASE WHEN position>0 THEN 1 END) AS in_progress," +
- " COUNT(CASE WHEN downloaded=1 THEN 1 END) AS episodes_downloaded " +
- " FROM FeedItems LEFT JOIN FeedMedia ON FeedItems.id=FeedMedia.feeditem GROUP BY FeedItems.feed)" +
- " ON Feeds.id = feed ORDER BY Feeds.title COLLATE NOCASE ASC;";
-
- public Cursor getFeedStatisticsCursor() {
- return db.rawQuery(FEED_STATISTICS_QUERY, null);
- }
-
- /**
- * Helper class for opening the Antennapod database.
- */
- private static class PodDBHelper extends SQLiteOpenHelper {
- /**
- * Constructor.
- *
- * @param context Context to use
- * @param name Name of the database
- * @param factory to use for creating cursor objects
- * @param version number of the database
- */
- public PodDBHelper(final Context context, final String name,
- final CursorFactory factory, final int version) {
- super(context, name, factory, version);
- }
-
- @Override
- public void onCreate(final SQLiteDatabase db) {
- db.execSQL(CREATE_TABLE_FEEDS);
- db.execSQL(CREATE_TABLE_FEED_ITEMS);
- db.execSQL(CREATE_TABLE_FEED_IMAGES);
- db.execSQL(CREATE_TABLE_FEED_MEDIA);
- db.execSQL(CREATE_TABLE_DOWNLOAD_LOG);
- db.execSQL(CREATE_TABLE_QUEUE);
- db.execSQL(CREATE_TABLE_SIMPLECHAPTERS);
- }
-
- @Override
- public void onUpgrade(final SQLiteDatabase db, final int oldVersion,
- final int newVersion) {
- Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to "
- + newVersion + ".");
- if (oldVersion <= 1) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS + " ADD COLUMN "
- + KEY_TYPE + " TEXT");
- }
- if (oldVersion <= 2) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_SIMPLECHAPTERS
- + " ADD COLUMN " + KEY_LINK + " TEXT");
- }
- if (oldVersion <= 3) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + KEY_ITEM_IDENTIFIER + " TEXT");
- }
- if (oldVersion <= 4) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS + " ADD COLUMN "
- + KEY_FEED_IDENTIFIER + " TEXT");
- }
- if (oldVersion <= 5) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_DOWNLOAD_LOG
- + " ADD COLUMN " + KEY_REASON_DETAILED + " TEXT");
- db.execSQL("ALTER TABLE " + TABLE_NAME_DOWNLOAD_LOG
- + " ADD COLUMN " + KEY_DOWNLOADSTATUS_TITLE + " TEXT");
- }
- if (oldVersion <= 6) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_SIMPLECHAPTERS
- + " ADD COLUMN " + KEY_CHAPTER_TYPE + " INTEGER");
- }
- if (oldVersion <= 7) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + KEY_PLAYBACK_COMPLETION_DATE
- + " INTEGER");
- }
- if (oldVersion <= 8) {
- final int KEY_ID_POSITION = 0;
- final int KEY_MEDIA_POSITION = 1;
-
- // Add feeditem column to feedmedia table
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + KEY_FEEDITEM
- + " INTEGER");
- Cursor feeditemCursor = db.query(TABLE_NAME_FEED_ITEMS, new String[]{KEY_ID, KEY_MEDIA}, "? > 0", new String[]{KEY_MEDIA}, null, null, null);
- if (feeditemCursor.moveToFirst()) {
- db.beginTransaction();
- ContentValues contentValues = new ContentValues();
- do {
- long mediaId = feeditemCursor.getLong(KEY_MEDIA_POSITION);
- contentValues.put(KEY_FEEDITEM, feeditemCursor.getLong(KEY_ID_POSITION));
- db.update(TABLE_NAME_FEED_MEDIA, contentValues, KEY_ID + "=?", new String[]{String.valueOf(mediaId)});
- contentValues.clear();
- } while (feeditemCursor.moveToNext());
- db.setTransactionSuccessful();
- db.endTransaction();
- }
- feeditemCursor.close();
- }
- if (oldVersion <= 9) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
- + " ADD COLUMN " + KEY_AUTO_DOWNLOAD
- + " INTEGER DEFAULT 1");
- }
- if (oldVersion <= 10) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
- + " ADD COLUMN " + KEY_FLATTR_STATUS
- + " INTEGER");
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + KEY_FLATTR_STATUS
- + " INTEGER");
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + KEY_PLAYED_DURATION
- + " INTEGER");
- }
- if (oldVersion <= 11) {
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
- + " ADD COLUMN " + KEY_USERNAME
- + " TEXT");
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS
- + " ADD COLUMN " + KEY_PASSWORD
- + " TEXT");
- db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + KEY_IMAGE
- + " INTEGER");
- }
- }
- }
-}