package net.rdrei.android.scdl2;
import android.annotation.TargetApi;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import net.rdrei.android.scdl2.ApplicationPreferences.StorageType;
import net.rdrei.android.scdl2.api.entity.TrackEntity;
import java.io.File;
import java.io.IOException;
import roboguice.util.Ln;
import roboguice.util.SafeAsyncTask;
/**
* Class for handling the downloading of tracks.
*
* @author pascal
*/
public class TrackDownloaderImpl implements TrackDownloader {
@Inject
private Context mContext;
@Inject
private DownloadManager mDownloadManager;
@Inject
private ApplicationPreferences mPreferences;
@Inject
private Tracker mTracker;
private final Uri mUri;
private final TrackEntity mTrack;
private final Handler mHandler;
@Inject
public TrackDownloaderImpl(@Assisted final Uri mUri, @Assisted final TrackEntity mTrack,
@Assisted final Handler handler) {
super();
this.mUri = mUri;
this.mTrack = mTrack;
mHandler = handler;
}
/*
* (non-Javadoc)
*
* @see net.rdrei.android.scdl2.TrackDownloader#enqueue()
*/
@Override
public void enqueue() throws IOException {
final StartDownloadTask startDownloadTask = new StartDownloadTask(mHandler);
startDownloadTask.execute();
}
/**
* Check if the given path is writable and attempts to create it.
*/
public static boolean checkAndCreateTypePath(final File path) {
if (!path.exists()) {
Ln.i("Path %s doesn't exist, creating...", path.toString());
if (!path.mkdirs()) {
Ln.w("Creating directory failed!");
return false;
}
}
if (BuildConfig.DEBUG) {
Ln.d("checkAndCreateTypePath isDirectory:" + path.isDirectory());
Ln.d("checkAndCreateTypePath canWrite:" + path.canWrite());
}
return path.isDirectory() && path.canWrite();
}
/**
* Creates a new download manager request based on the given uri.
*
* @param uri
* @return
* @throws IOException If directory can't be used for saving the file.
*/
@TargetApi(11)
private DownloadManager.Request createDownloadRequest(final Uri uri) throws IOException {
final Request request = new Request(uri);
setRequestStorage(request);
request.setTitle(mTrack.getTitle());
request.setDescription(mContext.getString(R.string.download_description));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// We have an audio file, please scan it!
request.allowScanningByMediaScanner();
}
return request;
}
private void setRequestStorage(final Request request) throws IOException {
final StorageType type = mPreferences.getStorageType();
final File typePath = mPreferences.getStorageDirectory();
String filename = mTrack.getDownloadFilename();
if (type == StorageType.LOCAL) {
filename += Config.TMP_DOWNLOAD_POSTFIX;
}
// The preferences panel already tries to create the path, but it could
// have been removed in the meantime, so we rather double-check.
if (!checkAndCreateTypePath(typePath)) {
throw new IOException(
String.format("Can't open directory %s to write.", typePath.toString()));
}
final Uri destinationUri = Uri.withAppendedPath(Uri.fromFile(typePath), filename);
Ln.d("Local destination URI: %s", destinationUri.toString());
request.setDestinationUri(destinationUri);
}
private class StartDownloadTask extends SafeAsyncTask<Void> {
public StartDownloadTask(final Handler handler) {
super(handler);
}
@Override
public Void call() throws Exception {
Ln.d("Starting download of %s.", mUri.toString());
final Request request;
request = createDownloadRequest(mUri);
mDownloadManager.enqueue(request);
return null;
}
/**
* Catches exceptions during the creation of the download request and bubbles them up using
* the provided handler.
*/
@Override
protected void onException(final Exception e) throws RuntimeException {
super.onException(e);
final Message msg;
Ln.i("Track download exception encountered.", e);
if (handler == null) {
trackDownloadError("DOWNLOAD_HANDLER_ERROR");
return;
}
if (e instanceof IOException) {
msg = handler.obtainMessage(MSG_DOWNLOAD_STORAGE_ERROR);
trackDownloadError("DOWNLOAD_STORAGE_ERROR");
} else {
msg = handler.obtainMessage(MSG_DOWNLOAD_ERROR);
trackDownloadError("DOWNLOAD_REQUEST_ERROR");
}
handler.sendMessage(msg);
}
private void trackDownloadError(final String description) {
mTracker.send(
new HitBuilders.ExceptionBuilder()
.setDescription(description)
.setFatal(false)
.build()
);
}
}
}