Cancel auto download

This commit is contained in:
Martin Fietz 2015-05-04 23:47:34 +02:00
parent 11a66f451a
commit c8259daaee
10 changed files with 191 additions and 100 deletions

View File

@ -12,9 +12,11 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
@ -75,7 +77,12 @@ public class DefaultActionButtonCallback implements ActionButtonCallback {
}
} else if (isDownloading) {
DownloadRequester.getInstance().cancelDownload(context, media);
Toast.makeText(context, R.string.download_cancelled_msg, Toast.LENGTH_SHORT).show();
if(UserPreferences.isEnableAutodownload()) {
DBWriter.setFeedItemAutoDownload(context, media.getItem(), false);
Toast.makeText(context, R.string.download_cancelled_autodownload_enabled_msg, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, R.string.download_cancelled_msg, Toast.LENGTH_LONG).show();
}
} else { // media is downloaded
if (item.hasMedia() && item.getMedia().isCurrentlyPlaying()) {
context.sendBroadcast(new Intent(PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));

View File

@ -13,7 +13,7 @@ public class StorageCallbacksImpl implements StorageCallbacks {
@Override
public int getDatabaseVersion() {
return 14;
return 15;
}
@Override
@ -124,5 +124,15 @@ public class StorageCallbacksImpl implements StorageCallbacks {
PodDBAdapter.KEY_LINK,
PodDBAdapter.KEY_CHAPTER_TYPE));
}
if(oldVersion <= 14) {
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
+ " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD + " INTEGER");
db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
+ " SET " + PodDBAdapter.KEY_AUTO_DOWNLOAD + " = "
+ "(SELECT " + PodDBAdapter.KEY_AUTO_DOWNLOAD
+ " FROM " + PodDBAdapter.TABLE_NAME_FEEDS
+ " WHERE " + PodDBAdapter.TABLE_NAME_FEEDS + "." + PodDBAdapter.KEY_ID
+ " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_FEED + ")");
}
}
}

View File

@ -5,15 +5,21 @@ import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.view.View;
import android.widget.ListView;
import android.widget.Toast;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadlistAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import java.util.List;
/**
* Displays all running downloads and provides actions to cancel them
*/
@ -73,7 +79,17 @@ public class RunningDownloadsFragment extends ListFragment {
@Override
public void onSecondaryActionClick(Downloader downloader) {
DownloadRequester.getInstance().cancelDownload(getActivity(), downloader.getDownloadRequest().getSource());
DownloadRequest downloadRequest = downloader.getDownloadRequest();
DownloadRequester.getInstance().cancelDownload(getActivity(), downloadRequest.getSource());
if(downloadRequest.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA &&
UserPreferences.isEnableAutodownload()) {
FeedMedia media = DBReader.getFeedMedia(getActivity(), downloadRequest.getFeedfileId());
DBWriter.setFeedItemAutoDownload(getActivity(), media.getItem(), false);
Toast.makeText(getActivity(), R.string.download_cancelled_autodownload_enabled_msg, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), R.string.download_cancelled_msg, Toast.LENGTH_SHORT).show();
}
}
};
}

View File

@ -63,6 +63,8 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
private List<Chapter> chapters;
private FeedImage image;
private boolean autoDownload = true;
public FeedItem() {
this.read = true;
this.flattrStatus = new FlattrStatus();
@ -74,7 +76,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
* */
public FeedItem(long id, String title, String link, Date pubDate, String paymentLink, long feedId,
FlattrStatus flattrStatus, boolean hasChapters, FeedImage image, boolean read,
String itemIdentifier) {
String itemIdentifier, boolean autoDownload) {
this.id = id;
this.title = title;
this.link = link;
@ -86,6 +88,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
this.image = image;
this.read = read;
this.itemIdentifier = itemIdentifier;
this.autoDownload = autoDownload;
}
/**
@ -388,6 +391,22 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
return hasChapters;
}
public void setAutoDownload(boolean autoDownload) {
this.autoDownload = autoDownload;
}
public boolean getAutoDownload() {
return this.autoDownload;
}
public boolean isAutoDownloadable() {
return this.hasMedia() &&
false == this.getMedia().isPlaying() &&
false == this.getMedia().isDownloaded() &&
false == this.isRead() &&
this.getAutoDownload();
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);

View File

@ -4,10 +4,9 @@ import android.content.Context;
import android.util.Log;
import java.util.ArrayList;
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;
@ -53,75 +52,53 @@ public class APDownloadAlgorithm implements AutomaticDownloadAlgorithm {
Log.d(TAG, "Performing auto-dl of undownloaded episodes");
final List<FeedItem> queue = DBReader.getQueue(context);
final List<FeedItem> unreadItems = DBReader
.getUnreadItemsList(context);
List<FeedItem> candidates;
if(mediaIds.length > 0) {
candidates = DBReader.getFeedItems(context, mediaIds);
} else {
final List<FeedItem> queue = DBReader.getQueue(context);
final List<FeedItem> unreadItems = DBReader.getUnreadItemsList(context);
candidates = new ArrayList<FeedItem>(queue.size() + unreadItems.size());
candidates.addAll(queue);
for(FeedItem unreadItem : unreadItems) {
if(candidates.contains(unreadItem) == false) {
candidates.add(unreadItem);
}
}
}
int undownloadedEpisodes = DBTasks.getNumberOfUndownloadedEpisodes(queue,
unreadItems);
int downloadedEpisodes = DBReader
.getNumberOfDownloadedEpisodes(context);
// filter items that are not auto downloadable
Iterator<FeedItem> it = candidates.iterator();
while(it.hasNext()) {
FeedItem item = it.next();
if(item.isAutoDownloadable() == false) {
it.remove();
}
}
int autoDownloadableEpisodes = candidates.size();
int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes(context);
int deletedEpisodes = cleanupAlgorithm.performCleanup(context,
APCleanupAlgorithm.getPerformAutoCleanupArgs(context, undownloadedEpisodes));
int episodeSpaceLeft = undownloadedEpisodes;
APCleanupAlgorithm.getPerformAutoCleanupArgs(context, autoDownloadableEpisodes));
boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences
.getEpisodeCacheSizeUnlimited();
int episodeCacheSize = UserPreferences.getEpisodeCacheSize();
if (!cacheIsUnlimited
&& UserPreferences.getEpisodeCacheSize() < downloadedEpisodes
+ undownloadedEpisodes) {
episodeSpaceLeft = UserPreferences.getEpisodeCacheSize()
- (downloadedEpisodes - deletedEpisodes);
int episodeSpaceLeft;
if (cacheIsUnlimited ||
episodeCacheSize >= downloadedEpisodes + autoDownloadableEpisodes) {
episodeSpaceLeft = autoDownloadableEpisodes;
} else {
episodeSpaceLeft = episodeCacheSize - (downloadedEpisodes - deletedEpisodes);
}
Arrays.sort(mediaIds); // sort for binary search
final boolean ignoreMediaIds = mediaIds.length == 0;
List<FeedItem> itemsToDownload = new ArrayList<FeedItem>();
FeedItem[] itemsToDownload = candidates.subList(0, episodeSpaceLeft)
.toArray(new FeedItem[episodeSpaceLeft]);
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");
Log.d(TAG, "Enqueueing " + itemsToDownload.length + " items for download");
try {
DBTasks.downloadFeedItems(false, context,
itemsToDownload.toArray(new FeedItem[itemsToDownload
.size()])
);
DBTasks.downloadFeedItems(false, context, itemsToDownload);
} catch (DownloadRequestException e) {
e.printStackTrace();
}
@ -130,4 +107,5 @@ public class APDownloadAlgorithm implements AutomaticDownloadAlgorithm {
}
};
}
}

View File

@ -4,6 +4,8 @@ import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@ -228,7 +230,9 @@ public final class DBReader {
itemlistCursor.getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0,
image,
(itemlistCursor.getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0),
itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER));
itemlistCursor.getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER),
itemlistCursor.getInt(itemlistCursor.getColumnIndex(PodDBAdapter.KEY_AUTO_DOWNLOAD)) > 0
);
itemIds.add(String.valueOf(item.getId()));
@ -719,6 +723,31 @@ public final class DBReader {
}
}
return item;
}
static List<FeedItem> getFeedItems(final Context context, PodDBAdapter adapter, final long... itemIds) {
String[] ids = new String[itemIds.length];
for(int i = 0; i < itemIds.length; i++) {
long itemId = itemIds[i];
ids[i] = Long.toString(itemId);
}
List<FeedItem> result;
Cursor itemCursor = adapter.getFeedItemCursor(ids);
if (itemCursor.moveToFirst()) {
result = extractItemlistFromCursor(adapter, itemCursor);
loadFeedDataOfFeedItemlist(context, result);
for(FeedItem item : result) {
if (item.hasChapters()) {
loadChaptersOfFeedItem(adapter, item);
}
}
} else {
result = Collections.emptyList();
}
return result;
}
@ -740,7 +769,6 @@ public final class DBReader {
FeedItem item = getFeedItem(context, itemId, adapter);
adapter.close();
return item;
}
static FeedItem getFeedItem(final Context context, final String podcastUrl, final String episodeUrl, PodDBAdapter adapter) {
@ -760,6 +788,26 @@ public final class DBReader {
return item;
}
/**
* Loads specific FeedItems from the database. This method canbe used for loading more
* than one FeedItem
*
* @param context A context that is used for opening a database connection.
* @param itemIds The IDs of the FeedItems
* @return The FeedItems or an empty list if none of the FeedItems could be found. All FeedComponent-attributes
* as well as chapter marks of the FeedItems will also be loaded from the database.
*/
public static List<FeedItem> getFeedItems(final Context context, final long... itemIds) {
Log.d(TAG, "Loading feeditem with ids: " + StringUtils.join(itemIds, ","));
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
List<FeedItem> items = getFeedItems(context, adapter, itemIds);
adapter.close();
return items;
}
/**
* Returns credentials based on image URL
*

View File

@ -428,25 +428,6 @@ public final class DBTasks {
}
}
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
@ -599,8 +580,7 @@ public final class DBTasks {
newFeedsList.add(newFeed);
resultFeeds[feedIdx] = newFeed;
} else {
if (BuildConfig.DEBUG)
Log.d(TAG, "Feed with title " + newFeed.getTitle()
Log.d(TAG, "Feed with title " + newFeed.getTitle()
+ " already exists. Syncing new with existing one.");
Collections.sort(newFeed.getItems(), new FeedItemPubdateComparator());
@ -608,21 +588,17 @@ public final class DBTasks {
final boolean markNewItemsAsUnread;
if (newFeed.getPageNr() == savedFeed.getPageNr()) {
if (savedFeed.compareWithOther(newFeed)) {
if (BuildConfig.DEBUG)
Log.d(TAG,
"Feed has updated attribute values. Updating old feed's attributes");
Log.d(TAG, "Feed has updated attribute values. Updating old feed's attributes");
savedFeed.updateFromOther(newFeed);
}
markNewItemsAsUnread = true;
} else {
if (BuildConfig.DEBUG)
Log.d(TAG, "New feed has a higher page number. Merging without marking as unread");
Log.d(TAG, "New feed has a higher page number. Merging without marking as unread");
markNewItemsAsUnread = false;
savedFeed.setNextPageLink(newFeed.getNextPageLink());
}
if (savedFeed.getPreferences().compareWithOther(newFeed.getPreferences())) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences");
Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences");
savedFeed.getPreferences().updateFromOther(newFeed.getPreferences());
}
// Look for new or updated Items
@ -634,6 +610,7 @@ public final class DBTasks {
// item is new
final int i = idx;
item.setFeed(savedFeed);
item.setAutoDownload(savedFeed.getPreferences().getAutoDownload());
savedFeed.getItems().add(i, item);
if (markNewItemsAsUnread) {
item.setRead(false);

View File

@ -1039,4 +1039,28 @@ public class DBWriter {
}
});
}
/**
* Sets the 'auto_download'-attribute of specific FeedItem.
*
* @param context A context that is used for opening a database connection.
* @param feedItem FeedItem.
*/
public static Future<?> setFeedItemAutoDownload(final Context context, final FeedItem feedItem,
final boolean autoDownload) {
Log.d(TAG, "FeedItem[id=" + feedItem.getId() + "] SET auto_download " + autoDownload);
return dbExec.submit(new Runnable() {
@Override
public void run() {
final PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
adapter.setFeedItemAutoDownload(feedItem, autoDownload);
adapter.close();
EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
}
});
}
}

View File

@ -186,7 +186,8 @@ public class PodDBAdapter {
+ KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER,"
+ KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT,"
+ KEY_FLATTR_STATUS + " INTEGER,"
+ KEY_IMAGE + " INTEGER)";
+ KEY_IMAGE + " INTEGER,"
+ KEY_AUTO_DOWNLOAD + " INTEGER)";
public static final String CREATE_TABLE_FEED_IMAGES = "CREATE TABLE "
+ TABLE_NAME_FEED_IMAGES + " (" + TABLE_PRIMARY_KEY + KEY_TITLE
@ -286,7 +287,9 @@ public class PodDBAdapter {
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};
TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE,
TABLE_NAME_FEED_ITEMS + "." + KEY_AUTO_DOWNLOAD
};
/**
* Contains FEEDITEM_SEL_FI_SMALL as comma-separated list. Useful for raw queries.
@ -696,6 +699,7 @@ public class PodDBAdapter {
values.put(KEY_HAS_CHAPTERS, item.getChapters() != null || item.hasChapters());
values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier());
values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong());
values.put(KEY_AUTO_DOWNLOAD, item.getAutoDownload());
if (item.hasItemImage()) {
if (item.getImage().getId() == 0) {
setImage(item.getImage());
@ -787,6 +791,13 @@ public class PodDBAdapter {
return status.getId();
}
public void setFeedItemAutoDownload(FeedItem feedItem, boolean autoDownload) {
ContentValues values = new ContentValues();
values.put(KEY_AUTO_DOWNLOAD, autoDownload);
db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?",
new String[] { String.valueOf(feedItem.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);

View File

@ -129,6 +129,7 @@
<string name="download_error_unauthorized">Authentication error</string>
<string name="cancel_all_downloads_label">Cancel all downloads</string>
<string name="download_cancelled_msg">Download cancelled</string>
<string name="download_cancelled_autodownload_enabled_msg">Download cancelled\nDisabled <i>Auto Download</i> for this item</string>
<string name="download_report_title">Downloads completed with error(s)</string>
<string name="download_report_content_title">Download report</string>
<string name="download_error_malformed_url">Malformed URL</string>