package org.redcross.openmapkit.deployments;
import android.app.Activity;
import android.app.DownloadManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import org.json.JSONArray;
import org.json.JSONObject;
import org.redcross.openmapkit.ExternalStorage;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class DeploymentDownloader extends AsyncTask<Void, Void, Void> {
private Set<DeploymentDownloaderListener> listeners = new HashSet<>();
private DownloadManager downloadManager;
private Deployment deployment;
private long[] downloadIds;
private boolean downloading = false;
private boolean canceled = false;
private long bytesDownloaded = 0;
private int filesCompleted = 0;
public DeploymentDownloader(Deployment deployment, Activity activity) {
downloadManager = (DownloadManager)activity.getSystemService(Activity.DOWNLOAD_SERVICE);
this.deployment = deployment;
downloadIds = new long[deployment.fileCount()];
if (activity instanceof DeploymentDownloaderListener) {
addListener((DeploymentDownloaderListener)activity);
}
}
public void addListener(DeploymentDownloaderListener listener) {
listeners.add(listener);
}
public void cancel() {
canceled = true;
downloading = false;
for (long id : downloadIds) {
if (id > -1) {
downloadManager.remove(id);
}
}
notifyDeploymentDownloadCanceled();
}
public boolean isDownloading() {
return downloading;
}
@Override
protected void onPreExecute() {
canceled = false;
downloading = true;
String msg = progressMsg();
notifyDeploymentDownloadProgressUpdate(msg, 0);
}
@Override
protected Void doInBackground(Void... nothing) {
// We want to start fresh for a download, because we don't want duplicates of a file.
ExternalStorage.deleteDeployment(deployment.name());
deployment.writeJSONToDisk();
String deploymentDir = ExternalStorage.deploymentDirRelativeToExternalDir(deployment.name());
int idx = 0;
List<JSONObject> files = deployment.filesToDownload();
for (JSONObject f : files) {
String url = f.optString("url");
if (url == null) continue;
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDestinationInExternalPublicDir(deploymentDir, Deployment.fileNameFromUrl(url));
long downloadId = downloadManager.enqueue(request);
downloadIds[idx++] = downloadId;
}
pollDownloadManager();
return null;
}
@Override
protected void onProgressUpdate(Void... nothing) {
String msg = progressMsg();
notifyDeploymentDownloadProgressUpdate(msg, bytesDownloaded);
}
@Override
protected void onPostExecute(Void nothing) {
if (canceled) return;
notifyDeploymentDownloadComplete();
}
private String progressMsg() {
return "Downloading deployment. "
+ filesCompleted + "/"
+ deployment.fileCount()
+ " files. "
+ ((double)bytesDownloaded) / 1000000.0 + " MB.";
}
private void notifyDeploymentDownloadProgressUpdate(String msg, long bytesDownloaded) {
for (DeploymentDownloaderListener listener : listeners) {
if (listener != null) {
listener.onDeploymentDownloadProgressUpdate(msg, bytesDownloaded);
}
}
}
private void notifyDeploymentDownloadComplete() {
for (DeploymentDownloaderListener listener : listeners) {
if (listener != null) {
listener.onDeploymentDownloadComplete();
}
}
}
private void notifyDeploymentDownloadCanceled() {
for (DeploymentDownloaderListener listener : listeners) {
if (listener != null) {
listener.onDeploymentDownloadCancel();
}
}
}
private void pollDownloadManager() {
while (downloading) {
DownloadManager.Query q = new DownloadManager.Query();
q.setFilterById(downloadIds);
Cursor cursor = downloadManager.query(q);
bytesDownloaded = 0;
filesCompleted = 0;
while(cursor.moveToNext()) {
bytesDownloaded += cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status != DownloadManager.STATUS_PENDING && status != DownloadManager.STATUS_RUNNING) {
++filesCompleted;
}
}
if (!canceled) {
publishProgress();
}
if (deployment.fileCount() == filesCompleted) {
downloading = false;
}
// throttle the thread
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}