package org.fdroid.fdroid.net;
import android.support.annotation.Nullable;
import android.util.Log;
import org.apache.commons.io.input.BoundedInputStream;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.net.bluetooth.BluetoothClient;
import org.fdroid.fdroid.net.bluetooth.BluetoothConnection;
import org.fdroid.fdroid.net.bluetooth.FileDetails;
import org.fdroid.fdroid.net.bluetooth.httpish.Request;
import org.fdroid.fdroid.net.bluetooth.httpish.Response;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class BluetoothDownloader extends Downloader {
private static final String TAG = "BluetoothDownloader";
private final BluetoothConnection connection;
private FileDetails fileDetails;
private final String sourcePath;
public BluetoothDownloader(String macAddress, URL sourceUrl, File destFile) throws IOException {
super(sourceUrl, destFile);
this.connection = new BluetoothClient(macAddress).openConnection();
this.sourcePath = sourceUrl.getPath();
}
@Override
protected InputStream getDownloadersInputStream() throws IOException {
Request request = Request.createGET(sourcePath, connection);
Response response = request.send();
fileDetails = response.toFileDetails();
// TODO: Manage the dependency which includes this class better?
// Right now, I only needed the one class from apache commons.
// There are countless classes online which provide this functionality,
// including some which are available from the Android SDK - the only
// problem is that they have a funky API which doesn't just wrap a
// plain old InputStream (the class is ContentLengthInputStream -
// whereas this BoundedInputStream is much more generic and useful
// to us).
BoundedInputStream stream = new BoundedInputStream(response.toContentStream(), fileDetails.getFileSize());
stream.setPropagateClose(false);
return stream;
}
/**
* May return null if an error occurred while getting file details.
*/
@Nullable
private FileDetails getFileDetails() {
if (fileDetails == null) {
Utils.debugLog(TAG, "Going to Bluetooth \"server\" to get file details.");
try {
fileDetails = Request.createHEAD(sourceUrl.getPath(), connection).send().toFileDetails();
} catch (IOException e) {
Log.e(TAG, "Error getting file details from Bluetooth \"server\"", e);
}
}
return fileDetails;
}
@Override
public boolean hasChanged() {
FileDetails details = getFileDetails();
return details == null || details.getCacheTag() == null || details.getCacheTag().equals(getCacheTag());
}
@Override
public int totalDownloadSize() {
FileDetails details = getFileDetails();
return details != null ? details.getFileSize() : -1;
}
@Override
public void download() throws IOException, InterruptedException {
downloadFromStream(1024, false);
connection.closeQuietly();
}
@Override
public boolean isCached() {
FileDetails details = getFileDetails();
return details != null &&
details.getCacheTag() != null &&
details.getCacheTag().equals(getCacheTag());
}
@Override
protected void close() {
if (connection != null) {
connection.closeQuietly();
}
}
}