/*******************************************************************************
* Copyright 2012 Crazywater
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package de.knufficast.watchers;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import android.content.Context;
import android.util.Log;
import android.util.Pair;
import de.knufficast.App;
import de.knufficast.logic.DownloadTask;
import de.knufficast.logic.db.Configuration;
import de.knufficast.logic.db.DBEpisode;
import de.knufficast.logic.db.DBEpisode.DownloadState;
import de.knufficast.util.BooleanCallback;
import de.knufficast.util.Callback;
import de.knufficast.util.NetUtil;
import de.knufficast.util.file.ExternalFileUtil;
/**
* Handles downloads of the queue: Can restart downloads of not yet downloaded
* queue items and delete them.
*
* @author crazywater
*
*/
public class QueueDownloader {
private Context context;
private NetUtil netUtil;
private static QueueDownloader instance;
private Map<DBEpisode, DownloadTask> downloadTasks = new HashMap<DBEpisode, DownloadTask>();
private static final int MAX_DOWNLOAD_THREADS = 2;
private final BlockingQueue<Runnable> downloadTaskQueue = new LinkedBlockingQueue<Runnable>();
private final ThreadPoolExecutor downloadExecutor = new ThreadPoolExecutor(1,
MAX_DOWNLOAD_THREADS, 1, TimeUnit.SECONDS, downloadTaskQueue);
private QueueDownloader(Context context) {
this.context = context;
this.netUtil = new NetUtil(context);
}
public static QueueDownloader get() {
if (instance == null) {
instance = new QueueDownloader(App.get());
}
return instance;
}
public void cancelDownloads() {
for (Entry<DBEpisode, DownloadTask> entry : downloadTasks.entrySet()) {
entry.getValue().cancel(true);
entry.getKey().setDownloadState(DownloadState.PAUSED);
}
}
public void restartDownloads() {
Configuration config = App.get().getConfiguration();
if (netUtil.isOnWifi() || !config.downloadNeedsWifi()) {
for (final DBEpisode episode : App.get().getQueue().asList()) {
if (episode.getDownloadState() != DownloadState.FINISHED
&& episode.getDownloadState() != DownloadState.DOWNLOADING) {
final String url = episode.getDataUrl();
episode.setDownloadState(DownloadState.DOWNLOADING);
Callback<Pair<Long, Long>> progressCallback = new Callback<Pair<Long, Long>>() {
@Override
public void call(Pair<Long, Long> progress) {
episode.setDownloadProgress(progress.first, progress.second);
}
};
BooleanCallback<Void, String> finishedCallback = new BooleanCallback<Void, String>() {
@Override
public void success(Void unused) {
episode.setDownloadState(DownloadState.FINISHED);
downloadTasks.remove(episode);
}
@Override
public void fail(String error) {
episode.setDownloadState(DownloadState.ERROR);
downloadTasks.remove(episode);
}
};
DownloadTask task = new DownloadTask(context, progressCallback, finishedCallback);
downloadTasks.put(episode, task);
task.executeOnExecutor(downloadExecutor, url,
episode.getFileLocation());
}
}
}
}
public void deleteDownload(DBEpisode episode) {
if (downloadTasks.containsKey(episode)) {
downloadTasks.get(episode).cancel(true);
downloadTasks.remove(episode);
}
File file = new ExternalFileUtil(context).resolveFile(episode
.getFileLocation());
if (file.exists()) {
boolean deleted = file.delete();
if (!deleted) {
Log.e("QueueDownloader",
"Could not delete " + episode.getFileLocation());
}
}
episode.setDownloadProgress(0, episode.getTotalBytes());
episode.setDownloadState(DownloadState.NONE);
}
}