main commit

Post-processing infrastructure
* remove interfaces with one implementation
* fix download resources with unknow length
* marquee style for ProgressDrawable
* "view details" option in mission context menu
* notification for finished downloads
* postprocessing infrastructure: sub-missions, circular file, layers for layers of abstractions for Java IO streams
* Mp4 muxing (only DASH brand)
* WebM muxing
* Captions downloading
* alert dialog for overwrite existing downloads finished or not.

Misc changes
* delete SQLiteDownloadDataSource.java
* delete DownloadMissionSQLiteHelper.java
* implement Localization from #114

Misc fixes (this branch)
* restore old mission listeners variables. Prevents registered listeners get de-referenced on low-end devices
* DownloadManagerService.checkForRunningMission() now return false if the mission has a error.
* use Intent.FLAG_ACTIVITY_NEW_TASK when launching an activity from gigaget threads (apparently it is required in old versions of android)

More changes
* proper error handling "infrastructure"
* queue instead of multiple downloads
* move serialized pending downloads (.giga files) to app data
* stop downloads when swicthing to mobile network (never works, see 2nd point)
* save the thread count for next downloads
* a lot of incoherences fixed
* delete DownloadManagerTest.java (too many changes to keep this file updated)
This commit is contained in:
kapodamy 2018-09-23 15:12:23 -03:00
parent 45fea983b9
commit 5825843f68
48 changed files with 4379 additions and 1119 deletions

View file

@ -1,74 +1,109 @@
package us.shandian.giga.get;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.channels.ClosedByInterruptException;
import static org.schabi.newpipe.BuildConfig.DEBUG;
// Single-threaded fallback mode
public class DownloadRunnableFallback implements Runnable {
private final DownloadMission mMission;
//private int mId;
private static final String TAG = "DownloadRunnableFallbac";
public DownloadRunnableFallback(DownloadMission mission) {
if (mission == null) throw new NullPointerException("mission is null");
//mId = id;
private final DownloadMission mMission;
private int retryCount = 0;
private BufferedInputStream ipt;
private RandomAccessFile f;
DownloadRunnableFallback(@NonNull DownloadMission mission) {
mMission = mission;
ipt = null;
f = null;
}
private void dispose() {
try {
if (ipt != null) ipt.close();
} catch (IOException e) {
// nothing to do
}
try {
if (f != null) f.close();
} catch (IOException e) {
// ¿ejected media storage? ¿file deleted? ¿storage ran out of space?
}
}
@Override
public void run() {
try {
URL url = new URL(mMission.url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
boolean done;
if (conn.getResponseCode() != 200 && conn.getResponseCode() != 206) {
notifyError(DownloadMission.ERROR_SERVER_UNSUPPORTED);
} else {
RandomAccessFile f = new RandomAccessFile(mMission.location + "/" + mMission.name, "rw");
f.seek(0);
BufferedInputStream ipt = new BufferedInputStream(conn.getInputStream());
byte[] buf = new byte[512];
int len = 0;
int start = 0;
while ((len = ipt.read(buf, 0, 512)) != -1 && mMission.running) {
f.write(buf, 0, len);
notifyProgress(len);
if (Thread.interrupted()) {
break;
}
}
f.close();
ipt.close();
if (!mMission.unknownLength) {
start = mMission.getBlockBytePosition(0);
if (DEBUG && start > 0) {
Log.i(TAG, "Resuming a single-thread download at " + start);
}
}
try {
int rangeStart = (mMission.unknownLength || start < 1) ? -1 : start;
HttpURLConnection conn = mMission.openConnection(1, rangeStart, -1);
// secondary check for the file length
if (!mMission.unknownLength) mMission.unknownLength = conn.getContentLength() == -1;
f = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
f.seek(mMission.offsets[mMission.current] + start);
ipt = new BufferedInputStream(conn.getInputStream());
byte[] buf = new byte[DownloadMission.BUFFER_SIZE];
int len = 0;
while (mMission.running && (len = ipt.read(buf, 0, buf.length)) != -1) {
f.write(buf, 0, len);
start += len;
mMission.notifyProgress(len);
if (Thread.interrupted()) break;
}
// if thread goes interrupted check if the last part is written. This avoid re-download the whole file
done = len == -1;
} catch (Exception e) {
notifyError(DownloadMission.ERROR_UNKNOWN);
dispose();
// save position
mMission.setThreadBytePosition(0, start);
if (e instanceof ClosedByInterruptException) return;
if (retryCount++ > mMission.maxRetry) {
mMission.notifyError(e);
return;
}
run();// try again
return;
}
if (mMission.errCode == -1 && mMission.running) {
notifyFinished();
}
}
dispose();
private void notifyProgress(final long len) {
synchronized (mMission) {
mMission.notifyProgress(len);
}
}
private void notifyError(final int err) {
synchronized (mMission) {
mMission.notifyError(err);
mMission.pause();
}
}
private void notifyFinished() {
synchronized (mMission) {
if (done) {
mMission.notifyFinished();
} else {
mMission.setThreadBytePosition(0, start);
}
}
}