diff options
Diffstat (limited to 'core/src/main/java/de/danoeh')
8 files changed, 306 insertions, 282 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java b/core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java index 1a2671555..6619e706b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java +++ b/core/src/main/java/de/danoeh/antennapod/core/ClientConfig.java @@ -21,7 +21,5 @@ public class ClientConfig { public static FlattrCallbacks flattrCallbacks; - public static StorageCallbacks storageCallbacks; - public static DBTasksCallbacks dbTasksCallbacks; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/StorageCallbacks.java b/core/src/main/java/de/danoeh/antennapod/core/StorageCallbacks.java deleted file mode 100644 index 5d1a0fffc..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/StorageCallbacks.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.danoeh.antennapod.core; - -import android.database.sqlite.SQLiteDatabase; - -/** - * Callbacks for the classes in the storage package of the core module. - */ -public interface StorageCallbacks { - - /** - * Returns the current version of the database. - * - * @return The non-negative version number of the database. - */ - public int getDatabaseVersion(); - - /** - * Upgrades the given database from an old version to a newer version. - * - * @param db The database that is supposed to be upgraded. - * @param oldVersion The old version of the database. - * @param newVersion The version that the database is supposed to be upgraded to. - */ - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion); - - -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java index 29ba721fe..25b3a9ae6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java @@ -177,10 +177,21 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource */ public boolean hasNewItems() { for (FeedItem item : items) { - if (item.getState() == FeedItem.State.UNREAD) { - if (item.getMedia() != null) { - return true; - } + if (item.isNew()) { + return true; + } + } + return false; + } + + /** + * Returns true if at least one item in the itemlist is unread. + * + */ + public boolean hasUnplayedItems() { + for (FeedItem item : items) { + if (false == item.isNew() && false == item.isPlayed()) { + return true; } } return false; diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APSPCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APSPCleanupAlgorithm.java deleted file mode 100644 index 420bbc09d..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/APSPCleanupAlgorithm.java +++ /dev/null @@ -1,139 +0,0 @@ -package de.danoeh.antennapod.core.storage; - -import android.content.Context; -import android.util.Log; - -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.ExecutionException; - -import de.danoeh.antennapod.core.feed.FeedItem; - -/** - * Implementation of the EpisodeCleanupAlgorithm interface used by AntennaPodSP apps. - */ -public class APSPCleanupAlgorithm implements EpisodeCleanupAlgorithm<Integer> { - private static final String TAG = "APSPCleanupAlgorithm"; - - final int numberOfNewAutomaticallyDownloadedEpisodes; - - public APSPCleanupAlgorithm(int numberOfNewAutomaticallyDownloadedEpisodes) { - this.numberOfNewAutomaticallyDownloadedEpisodes = numberOfNewAutomaticallyDownloadedEpisodes; - } - - /** - * Performs an automatic cleanup. Episodes that have been downloaded first will also be deleted first. - * The episode that is currently playing as well as the n most recent episodes (the exact value is determined - * by AppPreferences.numberOfNewAutomaticallyDownloadedEpisodes) will never be deleted. - * - * @param context - * @param episodeSize The maximum amount of space that should be freed by this method - * @return The number of episodes that have been deleted - */ - @Override - public int performCleanup(Context context, Integer episodeSize) { - Log.i(TAG, String.format("performAutoCleanup(%d)", episodeSize)); - if (episodeSize <= 0) { - return 0; - } - - List<FeedItem> candidates = getAutoCleanupCandidates(context); - List<FeedItem> deleteList = new ArrayList<FeedItem>(); - long deletedEpisodesSize = 0; - Collections.sort(candidates, new Comparator<FeedItem>() { - @Override - public int compare(FeedItem lhs, FeedItem rhs) { - File lFile = new File(lhs.getMedia().getFile_url()); - File rFile = new File(rhs.getMedia().getFile_url()); - if (!lFile.exists() || !rFile.exists()) { - return 0; - } - if (FileUtils.isFileOlder(lFile, rFile)) { - return -1; - } else { - return 1; - } - } - }); - // listened episodes will be deleted first - Iterator<FeedItem> it = candidates.iterator(); - if (it.hasNext()) { - for (FeedItem i = it.next(); it.hasNext() && deletedEpisodesSize <= episodeSize; i = it.next()) { - if (!i.getMedia().isPlaying() && i.getMedia().getPlaybackCompletionDate() != null) { - it.remove(); - deleteList.add(i); - deletedEpisodesSize += i.getMedia().getSize(); - } - } - } - - // delete unlistened old episodes if necessary - it = candidates.iterator(); - if (it.hasNext()) { - for (FeedItem i = it.next(); it.hasNext() && deletedEpisodesSize <= episodeSize; i = it.next()) { - if (!i.getMedia().isPlaying()) { - it.remove(); - deleteList.add(i); - deletedEpisodesSize += i.getMedia().getSize(); - } - } - } - for (FeedItem item : deleteList) { - try { - DBWriter.deleteFeedMediaOfItem(context, item.getMedia().getId()).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } - } - Log.i(TAG, String.format("performAutoCleanup(%d) deleted %d episodes and freed %d bytes of memory", - episodeSize, deleteList.size(), deletedEpisodesSize)); - return deleteList.size(); - } - - @Override - public Integer getDefaultCleanupParameter(Context context) { - return 0; - } - - @Override - public Integer getPerformCleanupParameter(Context context, List<FeedItem> items) { - int episodeSize = 0; - for (FeedItem item : items) { - if (item.hasMedia() && !item.getMedia().isDownloaded()) { - episodeSize += item.getMedia().getSize(); - } - } - return episodeSize; - } - - /** - * Returns list of FeedItems that have been downloaded, but are not one of the - * [numberOfNewAutomaticallyDownloadedEpisodes] most recent items. - */ - private List<FeedItem> getAutoCleanupCandidates(Context context) { - List<FeedItem> downloaded = new ArrayList<FeedItem>(DBReader.getDownloadedItems(context)); - List<FeedItem> recent = new ArrayList<FeedItem>(DBReader.getRecentlyPublishedEpisodes(context, - numberOfNewAutomaticallyDownloadedEpisodes)); - for (FeedItem r : recent) { - if (r.hasMedia() && r.getMedia().isDownloaded()) { - for (int i = 0; i < downloaded.size(); i++) { - if (downloaded.get(i).getId() == r.getId()) { - downloaded.remove(i); - break; - } - } - } - } - - return downloaded; - - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APSPDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APSPDownloadAlgorithm.java deleted file mode 100644 index f760ec0ce..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/APSPDownloadAlgorithm.java +++ /dev/null @@ -1,72 +0,0 @@ -package de.danoeh.antennapod.core.storage; - -import android.content.Context; -import android.util.Log; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.util.NetworkUtils; - -/** - * Implements the automatic download algorithm used by AntennaPodSP apps. - */ -public class APSPDownloadAlgorithm implements AutomaticDownloadAlgorithm { - private static final String TAG = "APSPDownloadAlgorithm"; - - private final int numberOfNewAutomaticallyDownloadedEpisodes; - - public APSPDownloadAlgorithm(int numberOfNewAutomaticallyDownloadedEpisodes) { - this.numberOfNewAutomaticallyDownloadedEpisodes = numberOfNewAutomaticallyDownloadedEpisodes; - } - - /** - * Downloads the most recent episodes automatically. The exact number of - * episodes that will be downloaded can be set in the AppPreferences. - * - * @param context Used for accessing the DB. - * @return A Runnable that will be submitted to an ExecutorService. - */ - @Override - public Runnable autoDownloadUndownloadedItems(final Context context, final long... mediaIds) { - return new Runnable() { - @Override - public void run() { - if (BuildConfig.DEBUG) - Log.d(TAG, "Performing auto-dl of undownloaded episodes"); - if (NetworkUtils.autodownloadNetworkAvailable(context) - && UserPreferences.isEnableAutodownload()) { - - Arrays.sort(mediaIds); - List<FeedItem> itemsToDownload = DBReader.getRecentlyPublishedEpisodes(context, - numberOfNewAutomaticallyDownloadedEpisodes); - Iterator<FeedItem> it = itemsToDownload.iterator(); - - for (FeedItem item = it.next(); it.hasNext(); item = it.next()) { - if (!item.hasMedia() - || item.getMedia().isDownloaded() - || Arrays.binarySearch(mediaIds, item.getMedia().getId()) < 0) { - it.remove(); - } - } - if (BuildConfig.DEBUG) - Log.d(TAG, "Enqueueing " + itemsToDownload.size() - + " items for automatic download"); - if (!itemsToDownload.isEmpty()) { - try { - DBTasks.downloadFeedItems(false, context, - itemsToDownload.toArray(new FeedItem[itemsToDownload - .size()])); - } catch (DownloadRequestException e) { - e.printStackTrace(); - } - } - } - } - }; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 0347c1b72..3b33c28df 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -22,6 +22,7 @@ import de.danoeh.antennapod.core.feed.FeedPreferences; import de.danoeh.antennapod.core.feed.ID3Chapter; import de.danoeh.antennapod.core.feed.SimpleChapter; import de.danoeh.antennapod.core.feed.VorbisCommentChapter; +import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.util.DownloadError; import de.danoeh.antennapod.core.util.LongIntMap; @@ -1139,27 +1140,42 @@ public final class DBReader { for(int i=0; i < feeds.size(); i++) { feedIds[i] = feeds.get(i).getId(); } - final LongIntMap numUnreadFeedItems = adapter.getNumberOfUnreadFeedItems(feedIds); - Collections.sort(feeds, new Comparator<Feed>() { - @Override - public int compare(Feed lhs, Feed rhs) { - long numUnreadLhs = numUnreadFeedItems.get(lhs.getId()); - Log.d(TAG, "feed with id " + lhs.getId() + " has " + numUnreadLhs + " unread items"); - long numUnreadRhs = numUnreadFeedItems.get(rhs.getId()); - Log.d(TAG, "feed with id " + rhs.getId() + " has " + numUnreadRhs + " unread items"); - if(numUnreadLhs > numUnreadRhs) { - // reverse natural order: podcast with most unplayed episodes first - return -1; - } else if(numUnreadLhs == numUnreadRhs) { + final LongIntMap feedCounters = adapter.getFeedCounters(feedIds); + + Comparator<Feed> comparator; + int feedOrder = UserPreferences.getFeedOrder(); + if(feedOrder == UserPreferences.ORDER_UNPLAYED_EPISODES) { + comparator = new Comparator<Feed>() { + @Override + public int compare(Feed lhs, Feed rhs) { + long counterLhs = feedCounters.get(lhs.getId()); + long counterRhs = feedCounters.get(rhs.getId()); + if(counterLhs > counterRhs) { + // reverse natural order: podcast with most unplayed episodes first + return -1; + } else if(counterLhs == counterRhs) { + return lhs.getTitle().compareTo(rhs.getTitle()); + } else { + return 1; + } + } + }; + } else { + comparator = new Comparator<Feed>() { + @Override + public int compare(Feed lhs, Feed rhs) { + if(lhs.getTitle() == null) { + return 1; + } return lhs.getTitle().compareTo(rhs.getTitle()); - } else { - return 1; } - } - }); + }; + } + + Collections.sort(feeds, comparator); int queueSize = adapter.getQueueSize(); int numNewItems = adapter.getNumberOfNewItems(); - NavDrawerData result = new NavDrawerData(feeds, queueSize, numNewItems, numUnreadFeedItems); + NavDrawerData result = new NavDrawerData(feeds, queueSize, numNewItems, feedCounters); adapter.close(); return result; } @@ -1168,14 +1184,16 @@ public final class DBReader { public List<Feed> feeds; public int queueSize; public int numNewItems; - public LongIntMap numUnreadFeedItems; + public LongIntMap feedCounters; - public NavDrawerData(List<Feed> feeds, int queueSize, int numNewItems, - LongIntMap numUnreadFeedItems) { + public NavDrawerData(List<Feed> feeds, + int queueSize, + int numNewItems, + LongIntMap feedIndicatorValues) { this.feeds = feeds; this.queueSize = queueSize; this.numNewItems = numNewItems; - this.numUnreadFeedItems = numUnreadFeedItems; + this.feedCounters = feedIndicatorValues; } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index 278d897b6..d0da0b194 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -409,8 +409,8 @@ public class DBWriter { if (item != null) { // add item to either front ot back of queue boolean addToFront = UserPreferences.enqueueAtFront(); - if(addToFront){ - queue.add(0+i, item); + if (addToFront) { + queue.add(0 + i, item); } else { queue.add(item); } @@ -610,7 +610,8 @@ public class DBWriter { public void run() { final PodDBAdapter adapter = new PodDBAdapter(context); adapter.open(); - adapter.setFeedItemRead(read, itemIds); + int played = read ? FeedItem.PLAYED : FeedItem.UNPLAYED; + adapter.setFeedItemRead(played, itemIds); adapter.close(); EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); } @@ -656,6 +657,35 @@ public class DBWriter { * @param context A context that is used for opening a database connection. * @param feedId ID of the Feed. */ + public static Future<?> markFeedSeen(final Context context, final long feedId) { + return dbExec.submit(new Runnable() { + + @Override + public void run() { + final PodDBAdapter adapter = new PodDBAdapter(context); + adapter.open(); + Cursor itemCursor = adapter.getNewItemsIdsCursor(feedId); + long[] ids = new long[itemCursor.getCount()]; + itemCursor.moveToFirst(); + for (int i = 0; i < ids.length; i++) { + ids[i] = itemCursor.getLong(0); + itemCursor.moveToNext(); + } + itemCursor.close(); + adapter.setFeedItemRead(FeedItem.UNPLAYED, ids); + adapter.close(); + + 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() { @@ -677,7 +707,6 @@ public class DBWriter { EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); } }); - } /** diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 50df0f0a7..c3466c621 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -9,6 +9,7 @@ import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; +import android.media.MediaMetadataRetriever; import android.text.TextUtils; import android.util.Log; @@ -18,7 +19,6 @@ import java.util.Arrays; import java.util.List; import de.danoeh.antennapod.core.BuildConfig; -import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.event.ProgressEvent; import de.danoeh.antennapod.core.feed.Chapter; @@ -28,13 +28,12 @@ import de.danoeh.antennapod.core.feed.FeedImage; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.FeedPreferences; +import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.util.LongIntMap; import de.danoeh.antennapod.core.util.flattr.FlattrStatus; import de.greenrobot.event.EventBus; -; - // TODO Remove media column from feeditem table /** @@ -369,8 +368,7 @@ public class PodDBAdapter { private static synchronized PodDBHelper getDbHelperSingleton(Context appContext) { if (dbHelperSingleton == null) { - dbHelperSingleton = new PodDBHelper(appContext, DATABASE_NAME, null, - ClientConfig.storageCallbacks.getDatabaseVersion()); + dbHelperSingleton = new PodDBHelper(appContext, DATABASE_NAME, null); } return dbHelperSingleton; } @@ -1114,6 +1112,20 @@ public class PodDBAdapter { } /** + * Returns a cursor which contains all items of a feed that are considered new. + * The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection. + */ + public final Cursor getNewItemsIdsCursor(long feedId) { + final String query = "SELECT " + KEY_ID + + " FROM " + TABLE_NAME_FEED_ITEMS + + " WHERE " + KEY_FEED + "=" + feedId + + " AND " + KEY_READ + "=" + FeedItem.NEW + + " ORDER BY " + KEY_PUBDATE + " DESC"; + Cursor c = db.rawQuery(query, null); + return c; + } + + /** * Returns a cursor which contains all feed items that are considered new. * The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection. */ @@ -1282,7 +1294,20 @@ public class PodDBAdapter { return result; } - public final LongIntMap getNumberOfUnreadFeedItems(long... feedIds) { + public final LongIntMap getFeedCounters(long... feedIds) { + int indicator = UserPreferences.getFeedIndicator(); + String whereRead; + if(indicator == UserPreferences.SHOW_NEW_UNPLAYED_SUM) { + whereRead = "(" + KEY_READ + "=" + FeedItem.NEW + + " OR " + KEY_READ + "=" + FeedItem.UNPLAYED + ")"; + } else if(indicator == UserPreferences.SHOW_NEW) { + whereRead = KEY_READ + "=" + FeedItem.NEW; + } else if(indicator == UserPreferences.SHOW_UNPLAYED) { + whereRead = KEY_READ + "=" + FeedItem.UNPLAYED; + } else { + return new LongIntMap(0); + } + // work around TextUtils.join wanting only boxed items // and StringUtils.join() causing NoSuchMethodErrors on MIUI StringBuilder builder = new StringBuilder(); @@ -1298,9 +1323,8 @@ public class PodDBAdapter { final String query = "SELECT " + KEY_FEED + ", COUNT(" + KEY_ID + ") AS count " + " FROM " + TABLE_NAME_FEED_ITEMS + " WHERE " + KEY_FEED + " IN (" + builder.toString() + ") " - + " AND (" + KEY_READ + "=" + FeedItem.NEW - + " OR " + KEY_READ + "=" + FeedItem.UNPLAYED + ")" - + " GROUP BY " + KEY_FEED; + + " AND " + whereRead + " GROUP BY " + KEY_FEED; + Cursor c = db.rawQuery(query, null); LongIntMap result = new LongIntMap(c.getCount()); if (c.moveToFirst()) { @@ -1454,6 +1478,8 @@ public class PodDBAdapter { */ private static class PodDBHelper extends SQLiteOpenHelper { + private final static int VERSION = 17; + private Context context; /** @@ -1462,11 +1488,10 @@ public class PodDBAdapter { * @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); + final CursorFactory factory) { + super(context, name, factory, VERSION); this.context = context; } @@ -1492,7 +1517,188 @@ public class PodDBAdapter { public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { EventBus.getDefault().post(ProgressEvent.start(context.getString(R.string.progress_upgrading_database))); - ClientConfig.storageCallbacks.onUpgrade(db, oldVersion, newVersion); + Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to " + + newVersion + "."); + if (oldVersion <= 1) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + + KEY_TYPE + " TEXT"); + } + if (oldVersion <= 2) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS + + " ADD COLUMN " + KEY_LINK + " TEXT"); + } + if (oldVersion <= 3) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + + " ADD COLUMN " + KEY_ITEM_IDENTIFIER + " TEXT"); + } + if (oldVersion <= 4) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN " + + KEY_FEED_IDENTIFIER + " TEXT"); + } + if (oldVersion <= 5) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG + + " ADD COLUMN " + KEY_REASON_DETAILED + " TEXT"); + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG + + " ADD COLUMN " + KEY_DOWNLOADSTATUS_TITLE + " TEXT"); + } + if (oldVersion <= 6) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS + + " ADD COLUMN " + KEY_CHAPTER_TYPE + " INTEGER"); + } + if (oldVersion <= 7) { + db.execSQL("ALTER TABLE " + PodDBAdapter.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 " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + + " ADD COLUMN " + KEY_FEEDITEM + + " INTEGER"); + Cursor feeditemCursor = db.query(PodDBAdapter.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(PodDBAdapter.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 " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_AUTO_DOWNLOAD + + " INTEGER DEFAULT 1"); + } + if (oldVersion <= 10) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_FLATTR_STATUS + + " INTEGER"); + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + + " ADD COLUMN " + KEY_FLATTR_STATUS + + " INTEGER"); + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + + " ADD COLUMN " + KEY_PLAYED_DURATION + + " INTEGER"); + } + if (oldVersion <= 11) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_USERNAME + + " TEXT"); + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_PASSWORD + + " TEXT"); + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + + " ADD COLUMN " + KEY_IMAGE + + " INTEGER"); + } + if (oldVersion <= 12) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_IS_PAGED + " INTEGER DEFAULT 0"); + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_NEXT_PAGE_LINK + " TEXT"); + } + if (oldVersion <= 13) { + // remove duplicate rows in "Chapters" table that were created because of a bug. + db.execSQL(String.format("DELETE FROM %s WHERE %s NOT IN " + + "(SELECT MIN(%s) as %s FROM %s GROUP BY %s,%s,%s,%s,%s)", + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS, + KEY_ID, + KEY_ID, + KEY_ID, + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS, + KEY_TITLE, + KEY_START, + KEY_FEEDITEM, + KEY_LINK, + KEY_CHAPTER_TYPE)); + } + if(oldVersion <= 14) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + + " ADD COLUMN " + KEY_AUTO_DOWNLOAD + " INTEGER"); + db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + + " SET " + KEY_AUTO_DOWNLOAD + " = " + + "(SELECT " + KEY_AUTO_DOWNLOAD + + " FROM " + PodDBAdapter.TABLE_NAME_FEEDS + + " WHERE " + PodDBAdapter.TABLE_NAME_FEEDS + "." + KEY_ID + + " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + ")"); + + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_HIDE + " TEXT"); + + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0"); + + // create indexes + db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_FEED); + db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_IMAGE); + db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDMEDIA_FEEDITEM); + db.execSQL(PodDBAdapter.CREATE_INDEX_QUEUE_FEEDITEM); + db.execSQL(PodDBAdapter.CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM); + } + if(oldVersion <= 15) { + db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + + " ADD COLUMN " + KEY_HAS_EMBEDDED_PICTURE + " INTEGER DEFAULT -1"); + db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + + " SET " + KEY_HAS_EMBEDDED_PICTURE + "=0" + + " WHERE " + KEY_DOWNLOADED + "=0"); + Cursor c = db.rawQuery("SELECT " + KEY_FILE_URL + + " FROM " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + + " WHERE " + KEY_DOWNLOADED + "=1 " + + " AND " + KEY_HAS_EMBEDDED_PICTURE + "=-1", null); + if(c.moveToFirst()) { + MediaMetadataRetriever mmr = new MediaMetadataRetriever(); + do { + String fileUrl = c.getString(0); + try { + mmr.setDataSource(fileUrl); + byte[] image = mmr.getEmbeddedPicture(); + if (image != null) { + db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + + " SET " + KEY_HAS_EMBEDDED_PICTURE + "=1" + + " WHERE " + KEY_FILE_URL + "='"+ fileUrl + "'"); + } else { + db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + + " SET " + KEY_HAS_EMBEDDED_PICTURE + "=0" + + " WHERE " + KEY_FILE_URL + "='"+ fileUrl + "'"); + } + } catch(Exception e) { + e.printStackTrace(); + } + } while(c.moveToNext()); + } + c.close(); + } + if(oldVersion <= 16) { + String selectNew = "SELECT " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_ID + + " FROM " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + + " INNER JOIN " + PodDBAdapter.TABLE_NAME_FEED_MEDIA + " ON " + + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "=" + + PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + KEY_FEEDITEM + + " LEFT OUTER JOIN " + PodDBAdapter.TABLE_NAME_QUEUE + " ON " + + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_ID + "=" + + PodDBAdapter.TABLE_NAME_QUEUE + "." + KEY_FEEDITEM + + " WHERE " + + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + KEY_READ + " = 0 AND " // unplayed + + PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + " = 0 AND " // undownloaded + + PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + KEY_POSITION + " = 0 AND " // not partially played + + PodDBAdapter.TABLE_NAME_QUEUE + "." + KEY_ID + " IS NULL"; // not in queue + String sql = "UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + + " SET " + KEY_READ + "=" + FeedItem.NEW + + " WHERE " + KEY_ID + " IN (" + selectNew + ")"; + Log.d("Migration", "SQL: " + sql); + db.execSQL(sql); + } EventBus.getDefault().post(ProgressEvent.end()); } } |