misc improvements
* don't show notifications while download activity * proper icon in failed download notifications * re-write list auto-refresh (MissionAdapter.java) * improve I/O performance (CircularFile.java) * fix implementation of "save thread position" on multi-thread downloads
This commit is contained in:
parent
f3d4d4747a
commit
eba3b32708
|
@ -416,7 +416,8 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||||
// fallback
|
// fallback
|
||||||
// 1st loop match country & language
|
// 1st loop match country & language
|
||||||
// 2nd loop match language only
|
// 2nd loop match language only
|
||||||
String lang = loc.getLanguage().substring(0, loc.getLanguage().indexOf("-"));
|
int index = loc.getLanguage().indexOf("-");
|
||||||
|
String lang = index > 0 ? loc.getLanguage().substring(0, index) : loc.getLanguage();
|
||||||
|
|
||||||
for (int j = 0; j < 2; j++) {
|
for (int j = 0; j < 2; j++) {
|
||||||
for (int i = 0; i < streams.size(); i++) {
|
for (int i = 0; i < streams.size(); i++) {
|
||||||
|
|
|
@ -221,12 +221,12 @@ public class DownloadMission extends Mission {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get position inside of the block, where thread will be resumed
|
* Get position inside of the thread, where thread will be resumed
|
||||||
*
|
*
|
||||||
* @param threadId the identifier of the thread
|
* @param threadId the identifier of the thread
|
||||||
* @return the relative position in bytes or zero
|
* @return the relative position in bytes or zero
|
||||||
*/
|
*/
|
||||||
long getBlockBytePosition(int threadId) {
|
long getThreadBytePosition(int threadId) {
|
||||||
return threadBytePositions.get(threadId);
|
return threadBytePositions.get(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,6 +256,8 @@ public class DownloadMission extends Mission {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conn.connect();
|
||||||
|
|
||||||
int statusCode = conn.getResponseCode();
|
int statusCode = conn.getResponseCode();
|
||||||
switch (statusCode) {
|
switch (statusCode) {
|
||||||
case 204:
|
case 204:
|
||||||
|
@ -446,6 +448,8 @@ public class DownloadMission extends Mission {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (postprocessingRunning) return;
|
||||||
|
|
||||||
// wait for all threads are suspended before save the state
|
// wait for all threads are suspended before save the state
|
||||||
runAsync(-1, () -> {
|
runAsync(-1, () -> {
|
||||||
try {
|
try {
|
||||||
|
@ -590,7 +594,7 @@ public class DownloadMission extends Mission {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return "Http status code" + String.valueOf(statusCode);
|
return "Http status code: " + String.valueOf(statusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,10 @@ package us.shandian.giga.get;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.channels.ClosedByInterruptException;
|
import java.nio.channels.ClosedByInterruptException;
|
||||||
|
|
||||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||||
|
@ -38,8 +37,8 @@ public class DownloadRunnable implements Runnable {
|
||||||
Log.d(TAG, mId + ":recovered: " + mMission.recovered);
|
Log.d(TAG, mId + ":recovered: " + mMission.recovered);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedInputStream ipt = null;
|
|
||||||
RandomAccessFile f;
|
RandomAccessFile f;
|
||||||
|
InputStream is = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
|
f = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
|
||||||
|
@ -82,9 +81,11 @@ public class DownloadRunnable implements Runnable {
|
||||||
mMission.preserveBlock(blockPosition);
|
mMission.preserveBlock(blockPosition);
|
||||||
mMission.setBlockPosition(mId, blockPosition);
|
mMission.setBlockPosition(mId, blockPosition);
|
||||||
|
|
||||||
long start = (blockPosition * DownloadMission.BLOCK_SIZE) + mMission.getBlockBytePosition(mId);
|
long start = blockPosition * DownloadMission.BLOCK_SIZE;
|
||||||
long end = start + DownloadMission.BLOCK_SIZE - 1;
|
long end = start + DownloadMission.BLOCK_SIZE - 1;
|
||||||
|
|
||||||
|
start += mMission.getThreadBytePosition(mId);
|
||||||
|
|
||||||
if (end >= mMission.length) {
|
if (end >= mMission.length) {
|
||||||
end = mMission.length - 1;
|
end = mMission.length - 1;
|
||||||
}
|
}
|
||||||
|
@ -107,11 +108,11 @@ public class DownloadRunnable implements Runnable {
|
||||||
|
|
||||||
f.seek(mMission.offsets[mMission.current] + start);
|
f.seek(mMission.offsets[mMission.current] + start);
|
||||||
|
|
||||||
ipt = new BufferedInputStream(conn.getInputStream());
|
is = conn.getInputStream();
|
||||||
byte[] buf = new byte[DownloadMission.BUFFER_SIZE];
|
byte[] buf = new byte[DownloadMission.BUFFER_SIZE];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
while (start < end && mMission.running && (len = ipt.read(buf, 0, buf.length)) != -1) {
|
while (start < end && mMission.running && (len = is.read(buf, 0, buf.length)) != -1) {
|
||||||
f.write(buf, 0, len);
|
f.write(buf, 0, len);
|
||||||
start += len;
|
start += len;
|
||||||
total += len;
|
total += len;
|
||||||
|
@ -119,7 +120,8 @@ public class DownloadRunnable implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG && mMission.running) {
|
if (DEBUG && mMission.running) {
|
||||||
Log.d(TAG, mId + ":position " + blockPosition + " finished, total length " + total);
|
Log.d(TAG, mId + ":position " + blockPosition + " finished, " + total + " bytes downloaded");
|
||||||
|
mMission.setThreadBytePosition(mId, 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the download is paused, save progress for this thread
|
// if the download is paused, save progress for this thread
|
||||||
|
@ -132,7 +134,7 @@ public class DownloadRunnable implements Runnable {
|
||||||
|
|
||||||
if (e instanceof ClosedByInterruptException) break;
|
if (e instanceof ClosedByInterruptException) break;
|
||||||
|
|
||||||
if (retryCount++ > mMission.maxRetry) {
|
if (retryCount++ >= mMission.maxRetry) {
|
||||||
mMission.notifyError(e);
|
mMission.notifyError(e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -140,6 +142,8 @@ public class DownloadRunnable implements Runnable {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, mId + ":position " + blockPosition + " retrying due exception", e);
|
Log.d(TAG, mId + ":position " + blockPosition + " retrying due exception", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +154,7 @@ public class DownloadRunnable implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (ipt != null) ipt.close();
|
if (is != null) is.close();
|
||||||
} catch (Exception err) {
|
} catch (Exception err) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ import android.annotation.SuppressLint;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.nio.channels.ClosedByInterruptException;
|
import java.nio.channels.ClosedByInterruptException;
|
||||||
|
@ -24,18 +24,18 @@ public class DownloadRunnableFallback implements Runnable {
|
||||||
private final DownloadMission mMission;
|
private final DownloadMission mMission;
|
||||||
private int retryCount = 0;
|
private int retryCount = 0;
|
||||||
|
|
||||||
private BufferedInputStream ipt;
|
private InputStream is;
|
||||||
private RandomAccessFile f;
|
private RandomAccessFile f;
|
||||||
|
|
||||||
DownloadRunnableFallback(@NonNull DownloadMission mission) {
|
DownloadRunnableFallback(@NonNull DownloadMission mission) {
|
||||||
mMission = mission;
|
mMission = mission;
|
||||||
ipt = null;
|
is = null;
|
||||||
f = null;
|
f = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispose() {
|
private void dispose() {
|
||||||
try {
|
try {
|
||||||
if (ipt != null) ipt.close();
|
if (is != null) is.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ public class DownloadRunnableFallback implements Runnable {
|
||||||
long start = 0;
|
long start = 0;
|
||||||
|
|
||||||
if (!mMission.unknownLength) {
|
if (!mMission.unknownLength) {
|
||||||
start = mMission.getBlockBytePosition(0);
|
start = mMission.getThreadBytePosition(0);
|
||||||
if (DEBUG && start > 0) {
|
if (DEBUG && start > 0) {
|
||||||
Log.i(TAG, "Resuming a single-thread download at " + start);
|
Log.i(TAG, "Resuming a single-thread download at " + start);
|
||||||
}
|
}
|
||||||
|
@ -72,18 +72,15 @@ public class DownloadRunnableFallback implements Runnable {
|
||||||
f = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
|
f = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
|
||||||
f.seek(mMission.offsets[mMission.current] + start);
|
f.seek(mMission.offsets[mMission.current] + start);
|
||||||
|
|
||||||
ipt = new BufferedInputStream(conn.getInputStream());
|
is = conn.getInputStream();
|
||||||
|
|
||||||
byte[] buf = new byte[DownloadMission.BUFFER_SIZE];
|
byte[] buf = new byte[64 * 1024];
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
while (mMission.running && (len = ipt.read(buf, 0, buf.length)) != -1) {
|
while (mMission.running && (len = is.read(buf, 0, buf.length)) != -1) {
|
||||||
f.write(buf, 0, len);
|
f.write(buf, 0, len);
|
||||||
start += len;
|
start += len;
|
||||||
|
|
||||||
mMission.notifyProgress(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
|
// if thread goes interrupted check if the last part is written. This avoid re-download the whole file
|
||||||
|
@ -96,7 +93,7 @@ public class DownloadRunnableFallback implements Runnable {
|
||||||
|
|
||||||
if (e instanceof ClosedByInterruptException) return;
|
if (e instanceof ClosedByInterruptException) return;
|
||||||
|
|
||||||
if (retryCount++ > mMission.maxRetry) {
|
if (retryCount++ >= mMission.maxRetry) {
|
||||||
mMission.notifyError(e);
|
mMission.notifyError(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,10 @@ import java.util.ArrayList;
|
||||||
public class CircularFile extends SharpStream {
|
public class CircularFile extends SharpStream {
|
||||||
|
|
||||||
private final static int AUX_BUFFER_SIZE = 1024 * 1024;// 1 MiB
|
private final static int AUX_BUFFER_SIZE = 1024 * 1024;// 1 MiB
|
||||||
private final static int NOTIFY_BYTES_INTERVAL = 256 * 1024;// 256 KiB
|
private final static int AUX_BUFFER_SIZE2 = 512 * 1024;// 512 KiB
|
||||||
|
private final static int NOTIFY_BYTES_INTERVAL = 64 * 1024;// 64 KiB
|
||||||
private final static int QUEUE_BUFFER_SIZE = 8 * 1024;// 8 KiB
|
private final static int QUEUE_BUFFER_SIZE = 8 * 1024;// 8 KiB
|
||||||
|
private final static boolean IMMEDIATE_AUX_BUFFER_FLUSH = false;
|
||||||
|
|
||||||
private RandomAccessFile out;
|
private RandomAccessFile out;
|
||||||
private long position;
|
private long position;
|
||||||
|
@ -45,7 +47,7 @@ public class CircularFile extends SharpStream {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
auxiliaryBuffers = new ArrayList<>(1);
|
auxiliaryBuffers = new ArrayList<>(15);
|
||||||
callback = checker;
|
callback = checker;
|
||||||
startOffset = offset;
|
startOffset = offset;
|
||||||
reportPosition = offset;
|
reportPosition = offset;
|
||||||
|
@ -122,7 +124,7 @@ public class CircularFile extends SharpStream {
|
||||||
while (available > 0 && auxiliaryBuffers.size() > 0) {
|
while (available > 0 && auxiliaryBuffers.size() > 0) {
|
||||||
ManagedBuffer aux = auxiliaryBuffers.get(0);
|
ManagedBuffer aux = auxiliaryBuffers.get(0);
|
||||||
|
|
||||||
// check if there is enough space to dump the auxiliar buffer
|
// check if there is enough space to dump the auxiliary buffer
|
||||||
if (available >= (aux.size + queue.size)) {
|
if (available >= (aux.size + queue.size)) {
|
||||||
available -= aux.size;
|
available -= aux.size;
|
||||||
writeQueue(aux.buffer, 0, aux.size);
|
writeQueue(aux.buffer, 0, aux.size);
|
||||||
|
@ -131,26 +133,27 @@ public class CircularFile extends SharpStream {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try flush contents to avoid allocate another auxiliar buffer
|
if (IMMEDIATE_AUX_BUFFER_FLUSH) {
|
||||||
if (aux.available() < len && available > queue.size) {
|
// try flush contents to avoid allocate another auxiliary buffer
|
||||||
int size = Math.min(len, aux.available());
|
if (aux.available() < len && available > queue.size) {
|
||||||
aux.write(b, off, size);
|
int size = Math.min(len, aux.available());
|
||||||
|
aux.write(b, off, size);
|
||||||
|
|
||||||
off += size;
|
off += size;
|
||||||
len -= size;
|
len -= size;
|
||||||
|
|
||||||
size = Math.min(aux.size, (int) available - queue.size);
|
size = Math.min(aux.size, (int) available - queue.size);
|
||||||
if (size < 1) {
|
if (size < 1) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeQueue(aux.buffer, 0, size);
|
||||||
|
aux.dereference(size);
|
||||||
|
|
||||||
|
available -= size;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
writeQueue(aux.buffer, 0, size);
|
|
||||||
aux.dereference(size);
|
|
||||||
|
|
||||||
available -= size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
|
@ -174,7 +177,7 @@ public class CircularFile extends SharpStream {
|
||||||
if (available < 1) {
|
if (available < 1) {
|
||||||
// secondary auxiliary buffer
|
// secondary auxiliary buffer
|
||||||
available = len;
|
available = len;
|
||||||
aux = new ManagedBuffer(Math.max(len, AUX_BUFFER_SIZE));
|
aux = new ManagedBuffer(Math.max(len, AUX_BUFFER_SIZE2));
|
||||||
auxiliaryBuffers.add(aux);
|
auxiliaryBuffers.add(aux);
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -184,10 +187,7 @@ public class CircularFile extends SharpStream {
|
||||||
aux.write(b, off, (int) available);
|
aux.write(b, off, (int) available);
|
||||||
|
|
||||||
len -= available;
|
len -= available;
|
||||||
if (len < 1) {
|
if (len > 0) off += available;
|
||||||
break;
|
|
||||||
}
|
|
||||||
off += available;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,12 +361,8 @@ public class CircularFile extends SharpStream {
|
||||||
if (amount > size) {
|
if (amount > size) {
|
||||||
throw new IndexOutOfBoundsException("Invalid dereference amount (" + amount + ">=" + size + ")");
|
throw new IndexOutOfBoundsException("Invalid dereference amount (" + amount + ">=" + size + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
size -= amount;
|
size -= amount;
|
||||||
|
System.arraycopy(buffer, amount, buffer, 0, size);
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
buffer[i] = buffer[amount + i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int available() {
|
protected int available() {
|
||||||
|
|
|
@ -277,6 +277,7 @@ public class DownloadManager {
|
||||||
mDownloadDataSource.deleteMission(mission);
|
mDownloadDataSource.deleteMission(mission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_DELETED);
|
||||||
mission.delete();
|
mission.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,8 +428,8 @@ public class DownloadManager {
|
||||||
if (!canDownloadInCurrentNetwork()) return false;
|
if (!canDownloadInCurrentNetwork()) return false;
|
||||||
|
|
||||||
for (DownloadMission mission : mMissionsPending) {
|
for (DownloadMission mission : mMissionsPending) {
|
||||||
if (!mission.running && mission.errCode != DownloadMission.ERROR_POSTPROCESSING_FAILED && mission.enqueued) {
|
if (!mission.running && mission.errCode == DownloadMission.ERROR_NOTHING && mission.enqueued) {
|
||||||
resumeMission(mMissionsPending.get(i));
|
resumeMission(mission);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.NotificationCompat.Builder;
|
import android.support.v4.app.NotificationCompat.Builder;
|
||||||
import android.support.v4.content.PermissionChecker;
|
import android.support.v4.content.PermissionChecker;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.SparseArray;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -36,7 +37,6 @@ import org.schabi.newpipe.player.helper.LockManager;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import us.shandian.giga.get.DownloadMission;
|
import us.shandian.giga.get.DownloadMission;
|
||||||
import us.shandian.giga.service.DownloadManager.NetworkState;
|
import us.shandian.giga.service.DownloadManager.NetworkState;
|
||||||
|
@ -46,13 +46,14 @@ import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||||
|
|
||||||
public class DownloadManagerService extends Service {
|
public class DownloadManagerService extends Service {
|
||||||
|
|
||||||
private static final String TAG = DownloadManagerService.class.getSimpleName();
|
private static final String TAG = "DownloadManagerService";
|
||||||
|
|
||||||
public static final int MESSAGE_RUNNING = 1;
|
public static final int MESSAGE_RUNNING = 0;
|
||||||
public static final int MESSAGE_PAUSED = 2;
|
public static final int MESSAGE_PAUSED = 1;
|
||||||
public static final int MESSAGE_FINISHED = 3;
|
public static final int MESSAGE_FINISHED = 2;
|
||||||
public static final int MESSAGE_PROGRESS = 4;
|
public static final int MESSAGE_PROGRESS = 3;
|
||||||
public static final int MESSAGE_ERROR = 5;
|
public static final int MESSAGE_ERROR = 4;
|
||||||
|
public static final int MESSAGE_DELETED = 5;
|
||||||
|
|
||||||
private static final int FOREGROUND_NOTIFICATION_ID = 1000;
|
private static final int FOREGROUND_NOTIFICATION_ID = 1000;
|
||||||
private static final int DOWNLOADS_NOTIFICATION_ID = 1001;
|
private static final int DOWNLOADS_NOTIFICATION_ID = 1001;
|
||||||
|
@ -67,17 +68,20 @@ public class DownloadManagerService extends Service {
|
||||||
private static final String EXTRA_SOURCE = "DownloadManagerService.extra.source";
|
private static final String EXTRA_SOURCE = "DownloadManagerService.extra.source";
|
||||||
private static final String EXTRA_NEAR_LENGTH = "DownloadManagerService.extra.nearLength";
|
private static final String EXTRA_NEAR_LENGTH = "DownloadManagerService.extra.nearLength";
|
||||||
|
|
||||||
private static final String ACTION_RESET_DOWNLOAD_COUNT = APPLICATION_ID + ".reset_download_count";
|
private static final String ACTION_RESET_DOWNLOAD_FINISHED = APPLICATION_ID + ".reset_download_finished";
|
||||||
|
private static final String ACTION_OPEN_DOWNLOADS_FINISHED = APPLICATION_ID + ".open_downloads_finished";
|
||||||
|
|
||||||
private DMBinder mBinder;
|
private DMBinder mBinder;
|
||||||
private DownloadManager mManager;
|
private DownloadManager mManager;
|
||||||
private Notification mNotification;
|
private Notification mNotification;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
|
private boolean mForeground = false;
|
||||||
|
private NotificationManager notificationManager = null;
|
||||||
|
private boolean mDownloadNotificationEnable = true;
|
||||||
|
|
||||||
private int downloadDoneCount = 0;
|
private int downloadDoneCount = 0;
|
||||||
private Builder downloadDoneNotification = null;
|
private Builder downloadDoneNotification = null;
|
||||||
private StringBuilder downloadDoneList = null;
|
private StringBuilder downloadDoneList = null;
|
||||||
NotificationManager notificationManager = null;
|
|
||||||
private boolean mForeground = false;
|
|
||||||
|
|
||||||
private final ArrayList<Handler> mEchoObservers = new ArrayList<>(1);
|
private final ArrayList<Handler> mEchoObservers = new ArrayList<>(1);
|
||||||
|
|
||||||
|
@ -90,9 +94,14 @@ public class DownloadManagerService extends Service {
|
||||||
private LockManager wakeLock = null;
|
private LockManager wakeLock = null;
|
||||||
|
|
||||||
private int downloadFailedNotificationID = DOWNLOADS_NOTIFICATION_ID + 1;
|
private int downloadFailedNotificationID = DOWNLOADS_NOTIFICATION_ID + 1;
|
||||||
|
private Builder downloadFailedNotification = null;
|
||||||
|
private SparseArray<DownloadMission> mFailedDownloads = new SparseArray<>(5);
|
||||||
|
|
||||||
private Bitmap icLauncher;
|
private Bitmap icLauncher;
|
||||||
private Bitmap icDownloadDone;
|
private Bitmap icDownloadDone;
|
||||||
|
private Bitmap icDownloadFailed;
|
||||||
|
|
||||||
|
private PendingIntent mOpenDownloadList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* notify media scanner on downloaded media file ...
|
* notify media scanner on downloaded media file ...
|
||||||
|
@ -124,14 +133,14 @@ public class DownloadManagerService extends Service {
|
||||||
Intent openDownloadListIntent = new Intent(this, DownloadActivity.class)
|
Intent openDownloadListIntent = new Intent(this, DownloadActivity.class)
|
||||||
.setAction(Intent.ACTION_MAIN);
|
.setAction(Intent.ACTION_MAIN);
|
||||||
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
|
mOpenDownloadList = PendingIntent.getActivity(this, 0,
|
||||||
openDownloadListIntent,
|
openDownloadListIntent,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
icLauncher = BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher);
|
icLauncher = BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher);
|
||||||
|
|
||||||
Builder builder = new Builder(this, getString(R.string.notification_channel_id))
|
Builder builder = new Builder(this, getString(R.string.notification_channel_id))
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(mOpenDownloadList)
|
||||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||||
.setLargeIcon(icLauncher)
|
.setLargeIcon(icLauncher)
|
||||||
.setContentTitle(getString(R.string.msg_running))
|
.setContentTitle(getString(R.string.msg_running))
|
||||||
|
@ -155,6 +164,9 @@ public class DownloadManagerService extends Service {
|
||||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
mPrefs.registerOnSharedPreferenceChangeListener(mPrefChangeListener);
|
mPrefs.registerOnSharedPreferenceChangeListener(mPrefChangeListener);
|
||||||
|
|
||||||
|
handlePreferenceChange(mPrefs, getString(R.string.downloads_cross_network));
|
||||||
|
handlePreferenceChange(mPrefs, getString(R.string.downloads_max_retry));
|
||||||
|
|
||||||
wakeLock = new LockManager(this);
|
wakeLock = new LockManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,9 +195,17 @@ public class DownloadManagerService extends Service {
|
||||||
|
|
||||||
mHandler.post(() -> mManager.startMission(urls, location, name, kind, threads, source, psName, psArgs, nearLength));
|
mHandler.post(() -> mManager.startMission(urls, location, name, kind, threads, source, psName, psArgs, nearLength));
|
||||||
|
|
||||||
} else if (downloadDoneNotification != null && action.equals(ACTION_RESET_DOWNLOAD_COUNT)) {
|
} else if (downloadDoneNotification != null) {
|
||||||
downloadDoneCount = 0;
|
if (action.equals(ACTION_RESET_DOWNLOAD_FINISHED) || action.equals(ACTION_OPEN_DOWNLOADS_FINISHED)) {
|
||||||
downloadDoneList.setLength(0);
|
downloadDoneCount = 0;
|
||||||
|
downloadDoneList.setLength(0);
|
||||||
|
}
|
||||||
|
if (action.equals(ACTION_OPEN_DOWNLOADS_FINISHED)) {
|
||||||
|
startActivity(new Intent(this, DownloadActivity.class)
|
||||||
|
.setAction(Intent.ACTION_MAIN)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return START_NOT_STICKY;
|
return START_NOT_STICKY;
|
||||||
|
@ -213,7 +233,8 @@ public class DownloadManagerService extends Service {
|
||||||
unregisterReceiver(mNetworkStateListener);
|
unregisterReceiver(mNetworkStateListener);
|
||||||
mPrefs.unregisterOnSharedPreferenceChangeListener(mPrefChangeListener);
|
mPrefs.unregisterOnSharedPreferenceChangeListener(mPrefChangeListener);
|
||||||
|
|
||||||
icDownloadDone.recycle();
|
if (icDownloadDone != null) icDownloadDone.recycle();
|
||||||
|
if (icDownloadFailed != null) icDownloadFailed.recycle();
|
||||||
icLauncher.recycle();
|
icLauncher.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +271,7 @@ public class DownloadManagerService extends Service {
|
||||||
updateForegroundState(true);
|
updateForegroundState(true);
|
||||||
break;
|
break;
|
||||||
case MESSAGE_ERROR:
|
case MESSAGE_ERROR:
|
||||||
notifyFailedDownload(mission.name);
|
notifyFailedDownload(mission);
|
||||||
updateForegroundState(mManager.runAnotherMission());
|
updateForegroundState(mManager.runAnotherMission());
|
||||||
break;
|
break;
|
||||||
case MESSAGE_PAUSED:
|
case MESSAGE_PAUSED:
|
||||||
|
@ -258,19 +279,16 @@ public class DownloadManagerService extends Service {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg.what != MESSAGE_ERROR)
|
||||||
|
mFailedDownloads.delete(mFailedDownloads.indexOfValue(mission));
|
||||||
|
|
||||||
synchronized (mEchoObservers) {
|
synchronized (mEchoObservers) {
|
||||||
Iterator<Handler> iterator = mEchoObservers.iterator();
|
for (Handler handler : mEchoObservers) {
|
||||||
while (iterator.hasNext()) {
|
Message echo = new Message();
|
||||||
Handler handler = iterator.next();
|
echo.what = msg.what;
|
||||||
if (handler.getLooper().getThread().isAlive()) {
|
echo.obj = msg.obj;
|
||||||
Message echo = new Message();
|
|
||||||
echo.what = msg.what;
|
handler.sendMessage(echo);
|
||||||
echo.obj = msg.obj;
|
|
||||||
handler.sendMessage(echo);
|
|
||||||
} else {
|
|
||||||
iterator.remove();// ¿missing call to removeMissionEventListener()?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,11 +324,14 @@ public class DownloadManagerService extends Service {
|
||||||
|
|
||||||
private void handlePreferenceChange(SharedPreferences prefs, String key) {
|
private void handlePreferenceChange(SharedPreferences prefs, String key) {
|
||||||
if (key.equals(getString(R.string.downloads_max_retry))) {
|
if (key.equals(getString(R.string.downloads_max_retry))) {
|
||||||
mManager.mPrefMaxRetry = Integer.parseInt(
|
try {
|
||||||
prefs.getString(key, getString(R.string.default_max_retry))
|
String value = prefs.getString(key, getString(R.string.downloads_max_retry_default));
|
||||||
);
|
mManager.mPrefMaxRetry = Integer.parseInt(value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
mManager.mPrefMaxRetry = 0;
|
||||||
|
}
|
||||||
mManager.updateMaximumAttempts();
|
mManager.updateMaximumAttempts();
|
||||||
} else if (key.equals(getString(R.string.cross_network_downloads))) {
|
} else if (key.equals(getString(R.string.downloads_cross_network))) {
|
||||||
mManager.mPrefCrossNetwork = prefs.getBoolean(key, false);
|
mManager.mPrefCrossNetwork = prefs.getBoolean(key, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,7 +389,7 @@ public class DownloadManagerService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyFinishedDownload(String name) {
|
public void notifyFinishedDownload(String name) {
|
||||||
if (notificationManager == null) {
|
if (!mDownloadNotificationEnable || notificationManager == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,14 +401,8 @@ public class DownloadManagerService extends Service {
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setLargeIcon(icDownloadDone)
|
.setLargeIcon(icDownloadDone)
|
||||||
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||||
.setDeleteIntent(PendingIntent.getService(this, (int) System.currentTimeMillis(),
|
.setDeleteIntent(makePendingIntent(ACTION_RESET_DOWNLOAD_FINISHED))
|
||||||
new Intent(this, DownloadManagerService.class)
|
.setContentIntent(makePendingIntent(ACTION_OPEN_DOWNLOADS_FINISHED));
|
||||||
.setAction(ACTION_RESET_DOWNLOAD_COUNT)
|
|
||||||
, PendingIntent.FLAG_UPDATE_CURRENT))
|
|
||||||
.setContentIntent(PendingIntent.getService(this, (int) System.currentTimeMillis() + 1,
|
|
||||||
new Intent(this, DownloadActivity.class)
|
|
||||||
.setAction(Intent.ACTION_MAIN),
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadDoneCount < 1) {
|
if (downloadDoneCount < 1) {
|
||||||
|
@ -417,33 +432,38 @@ public class DownloadManagerService extends Service {
|
||||||
downloadDoneCount++;
|
downloadDoneCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyFailedDownload(String name) {
|
public void notifyFailedDownload(DownloadMission mission) {
|
||||||
if (icDownloadDone == null) {
|
if (!mDownloadNotificationEnable || mFailedDownloads.indexOfValue(mission) >= 0) return;
|
||||||
// TODO: use a proper icon for failed downloads
|
|
||||||
icDownloadDone = BitmapFactory.decodeResource(this.getResources(), android.R.drawable.stat_sys_download_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
Builder notification = new Builder(this, getString(R.string.notification_channel_id))
|
int id = downloadFailedNotificationID++;
|
||||||
.setAutoCancel(true)
|
mFailedDownloads.put(id, mission);
|
||||||
.setLargeIcon(icDownloadDone)
|
|
||||||
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
if (downloadFailedNotification == null) {
|
||||||
.setContentIntent(PendingIntent.getService(this, (int) System.currentTimeMillis() + 1,
|
icDownloadFailed = BitmapFactory.decodeResource(this.getResources(), android.R.drawable.stat_sys_warning);
|
||||||
new Intent(this, DownloadActivity.class)
|
downloadFailedNotification = new Builder(this, getString(R.string.notification_channel_id))
|
||||||
.setAction(Intent.ACTION_MAIN),
|
.setAutoCancel(true)
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
.setLargeIcon(icDownloadFailed)
|
||||||
|
.setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||||
|
.setContentIntent(mOpenDownloadList);
|
||||||
|
}
|
||||||
|
|
||||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
notification.setContentTitle(getString(R.string.app_name));
|
downloadFailedNotification.setContentTitle(getString(R.string.app_name));
|
||||||
notification.setStyle(new NotificationCompat.BigTextStyle()
|
downloadFailedNotification.setStyle(new NotificationCompat.BigTextStyle()
|
||||||
.bigText(getString(R.string.download_failed).concat(": ").concat(name)));
|
.bigText(getString(R.string.download_failed).concat(": ").concat(mission.name)));
|
||||||
} else {
|
} else {
|
||||||
notification.setContentTitle(getString(R.string.download_failed));
|
downloadFailedNotification.setContentTitle(getString(R.string.download_failed));
|
||||||
notification.setContentText(name);
|
downloadFailedNotification.setContentText(mission.name);
|
||||||
notification.setStyle(new NotificationCompat.BigTextStyle()
|
downloadFailedNotification.setStyle(new NotificationCompat.BigTextStyle()
|
||||||
.bigText(name));
|
.bigText(mission.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationManager.notify(downloadFailedNotificationID++, notification.build());
|
notificationManager.notify(id, downloadFailedNotification.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private PendingIntent makePendingIntent(String action) {
|
||||||
|
Intent intent = new Intent(this, DownloadManagerService.class).setAction(action);
|
||||||
|
return PendingIntent.getService(this, intent.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void manageObservers(Handler handler, boolean add) {
|
private void manageObservers(Handler handler, boolean add) {
|
||||||
|
@ -470,12 +490,26 @@ public class DownloadManagerService extends Service {
|
||||||
manageObservers(handler, false);
|
manageObservers(handler, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetFinishedDownloadCount() {
|
public void clearDownloadNotifications() {
|
||||||
if (notificationManager == null || downloadDoneNotification == null) return;
|
if (notificationManager == null) return;
|
||||||
notificationManager.cancel(DOWNLOADS_NOTIFICATION_ID);
|
if (downloadDoneNotification != null) {
|
||||||
downloadDoneList.setLength(0);
|
notificationManager.cancel(DOWNLOADS_NOTIFICATION_ID);
|
||||||
downloadDoneCount = 0;
|
downloadDoneList.setLength(0);
|
||||||
|
downloadDoneCount = 0;
|
||||||
|
}
|
||||||
|
if (downloadFailedNotification != null) {
|
||||||
|
for (; downloadFailedNotificationID > DOWNLOADS_NOTIFICATION_ID; downloadFailedNotificationID--) {
|
||||||
|
notificationManager.cancel(downloadFailedNotificationID);
|
||||||
|
}
|
||||||
|
mFailedDownloads.clear();
|
||||||
|
downloadFailedNotificationID++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void enableNotifications(boolean enable) {
|
||||||
|
mDownloadNotificationEnable = enable;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface DMChecker {
|
public interface DMChecker {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.util.DiffUtil;
|
import android.support.v7.util.DiffUtil;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||||
|
import android.support.v7.widget.RecyclerView.Adapter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -40,7 +41,6 @@ import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import us.shandian.giga.get.DownloadMission;
|
import us.shandian.giga.get.DownloadMission;
|
||||||
import us.shandian.giga.get.FinishedMission;
|
import us.shandian.giga.get.FinishedMission;
|
||||||
|
@ -53,9 +53,10 @@ import us.shandian.giga.util.Utility;
|
||||||
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
|
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
|
||||||
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
||||||
|
|
||||||
public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
public class MissionAdapter extends Adapter<ViewHolder> {
|
||||||
private static final SparseArray<String> ALGORITHMS = new SparseArray<>();
|
private static final SparseArray<String> ALGORITHMS = new SparseArray<>();
|
||||||
private static final String TAG = "MissionAdapter";
|
private static final String TAG = "MissionAdapter";
|
||||||
|
private static final String UNDEFINED_SPEED = "--.-%";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ALGORITHMS.put(R.id.md5, "MD5");
|
ALGORITHMS.put(R.id.md5, "MD5");
|
||||||
|
@ -89,6 +90,7 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
case DownloadManagerService.MESSAGE_ERROR:
|
case DownloadManagerService.MESSAGE_ERROR:
|
||||||
case DownloadManagerService.MESSAGE_FINISHED:
|
case DownloadManagerService.MESSAGE_FINISHED:
|
||||||
onServiceMessage(msg);
|
onServiceMessage(msg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -120,7 +122,10 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
if (view instanceof ViewHolderHeader) return;
|
if (view instanceof ViewHolderHeader) return;
|
||||||
ViewHolderItem h = (ViewHolderItem) view;
|
ViewHolderItem h = (ViewHolderItem) view;
|
||||||
|
|
||||||
if (h.item.mission instanceof DownloadMission) mPendingDownloadsItems.remove(h);
|
if (h.item.mission instanceof DownloadMission) {
|
||||||
|
mPendingDownloadsItems.remove(h);
|
||||||
|
if (mPendingDownloadsItems.size() < 1) setAutoRefresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
h.popupMenu.dismiss();
|
h.popupMenu.dismiss();
|
||||||
h.item = null;
|
h.item = null;
|
||||||
|
@ -153,10 +158,11 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
h.item = item;
|
h.item = item;
|
||||||
|
|
||||||
Utility.FileType type = Utility.getFileType(item.mission.kind, item.mission.name);
|
Utility.FileType type = Utility.getFileType(item.mission.kind, item.mission.name);
|
||||||
|
long length = item.mission instanceof FinishedMission ? item.mission.length : ((DownloadMission) item.mission).getLength();
|
||||||
|
|
||||||
h.icon.setImageResource(Utility.getIconForFileType(type));
|
h.icon.setImageResource(Utility.getIconForFileType(type));
|
||||||
h.name.setText(item.mission.name);
|
h.name.setText(item.mission.name);
|
||||||
h.size.setText(Utility.formatBytes(item.mission.length));
|
h.size.setText(Utility.formatBytes(length));
|
||||||
|
|
||||||
h.progress.setColors(Utility.getBackgroundForFileType(mContext, type), Utility.getForegroundForFileType(mContext, type));
|
h.progress.setColors(Utility.getBackgroundForFileType(mContext, type), Utility.getForegroundForFileType(mContext, type));
|
||||||
|
|
||||||
|
@ -187,66 +193,60 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
private void updateProgress(ViewHolderItem h) {
|
private void updateProgress(ViewHolderItem h) {
|
||||||
if (h == null || h.item == null || h.item.mission instanceof FinishedMission) return;
|
if (h == null || h.item == null || h.item.mission instanceof FinishedMission) return;
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
DownloadMission mission = (DownloadMission) h.item.mission;
|
DownloadMission mission = (DownloadMission) h.item.mission;
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
|
|
||||||
if (h.lastTimeStamp == -1) {
|
|
||||||
h.lastTimeStamp = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h.lastDone == -1) {
|
|
||||||
h.lastDone = mission.done;
|
|
||||||
}
|
|
||||||
if (h.lastCurrent != mission.current) {
|
if (h.lastCurrent != mission.current) {
|
||||||
h.lastCurrent = mission.current;
|
h.lastCurrent = mission.current;
|
||||||
h.lastDone = 0;
|
|
||||||
h.lastTimeStamp = now;
|
h.lastTimeStamp = now;
|
||||||
|
h.lastDone = 0;
|
||||||
|
} else {
|
||||||
|
if (h.lastTimeStamp == -1) h.lastTimeStamp = now;
|
||||||
|
if (h.lastDone == -1) h.lastDone = mission.done;
|
||||||
}
|
}
|
||||||
|
|
||||||
long deltaTime = now - h.lastTimeStamp;
|
long deltaTime = now - h.lastTimeStamp;
|
||||||
long deltaDone = mission.done - h.lastDone;
|
long deltaDone = mission.done - h.lastDone;
|
||||||
boolean hasError = mission.errCode != DownloadMission.ERROR_NOTHING;
|
boolean hasError = mission.errCode != DownloadMission.ERROR_NOTHING;
|
||||||
|
|
||||||
if (hasError || deltaTime == 0 || deltaTime > 1000) {
|
// on error hide marquee or show if condition (mission.done < 1 || mission.unknownLength) is true
|
||||||
// on error hide marquee or show if condition (mission.done < 1 || mission.unknownLength) is true
|
h.progress.setMarquee(!hasError && (mission.done < 1 || mission.unknownLength));
|
||||||
h.progress.setMarquee(!hasError && (mission.done < 1 || mission.unknownLength));
|
|
||||||
|
|
||||||
float progress;
|
float progress;
|
||||||
if (mission.unknownLength) {
|
if (mission.unknownLength) {
|
||||||
progress = Float.NaN;
|
progress = Float.NaN;
|
||||||
h.progress.setProgress(0f);
|
h.progress.setProgress(0f);
|
||||||
} else {
|
} else {
|
||||||
progress = (float) ((double) mission.done / mission.length);
|
progress = (float) ((double) mission.done / mission.length);
|
||||||
if (mission.urls.length > 1 && mission.current < mission.urls.length) {
|
if (mission.urls.length > 1 && mission.current < mission.urls.length) {
|
||||||
progress = (progress / mission.urls.length) + ((float) mission.current / mission.urls.length);
|
progress = (progress / mission.urls.length) + ((float) mission.current / mission.urls.length);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
if (Float.isNaN(progress) || Float.isInfinite(progress))
|
if (Float.isNaN(progress) || Float.isInfinite(progress))
|
||||||
h.progress.setProgress(1f);
|
h.progress.setProgress(1f);
|
||||||
h.status.setText(R.string.msg_error);
|
h.status.setText(R.string.msg_error);
|
||||||
} else if (Float.isNaN(progress) || Float.isInfinite(progress)) {
|
} else if (Float.isNaN(progress) || Float.isInfinite(progress)) {
|
||||||
h.status.setText("--.-%");
|
h.status.setText(UNDEFINED_SPEED);
|
||||||
} else {
|
} else {
|
||||||
h.status.setText(String.format("%.2f%%", progress * 100));
|
h.status.setText(String.format("%.2f%%", progress * 100));
|
||||||
h.progress.setProgress(progress);
|
h.progress.setProgress(progress);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long length = mission.getLength();
|
long length = mission.getLength();
|
||||||
|
|
||||||
int state = 0;
|
int state;
|
||||||
if (!mission.isFinished()) {
|
if (!mission.running) {
|
||||||
if (!mission.running) {
|
state = mission.enqueued ? 1 : 2;
|
||||||
state = mission.enqueued ? 1 : 2;
|
} else if (mission.postprocessingRunning) {
|
||||||
} else if (mission.postprocessingRunning) {
|
state = 3;
|
||||||
state = 3;
|
} else {
|
||||||
}
|
state = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state != 0) {
|
if (state != 0) {
|
||||||
|
// update state without download speed
|
||||||
if (h.state != state) {
|
if (h.state != state) {
|
||||||
String statusStr;
|
String statusStr;
|
||||||
h.state = state;
|
h.state = state;
|
||||||
|
@ -267,7 +267,7 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
}
|
}
|
||||||
|
|
||||||
h.size.setText(Utility.formatBytes(length).concat(" (").concat(statusStr).concat(")"));
|
h.size.setText(Utility.formatBytes(length).concat(" (").concat(statusStr).concat(")"));
|
||||||
} else if (deltaTime > 1000 && deltaDone > 0) {
|
} else if (deltaDone > 0) {
|
||||||
h.lastTimeStamp = now;
|
h.lastTimeStamp = now;
|
||||||
h.lastDone = mission.done;
|
h.lastDone = mission.done;
|
||||||
}
|
}
|
||||||
|
@ -275,10 +275,10 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deltaDone > 0 && deltaTime > 0) {
|
||||||
|
float speed = (deltaDone * 1000f) / deltaTime;
|
||||||
|
|
||||||
if (deltaTime > 1000 && deltaDone > 0) {
|
String speedStr = Utility.formatSpeed(speed);
|
||||||
float speed = (float) ((double) deltaDone / deltaTime);
|
|
||||||
String speedStr = Utility.formatSpeed(speed * 1000);
|
|
||||||
String sizeStr = Utility.formatBytes(length);
|
String sizeStr = Utility.formatBytes(length);
|
||||||
|
|
||||||
h.size.setText(sizeStr.concat(" ").concat(speedStr));
|
h.size.setText(sizeStr.concat(" ").concat(speedStr));
|
||||||
|
@ -325,6 +325,8 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
private void onServiceMessage(@NonNull Message msg) {
|
private void onServiceMessage(@NonNull Message msg) {
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case DownloadManagerService.MESSAGE_PROGRESS:
|
case DownloadManagerService.MESSAGE_PROGRESS:
|
||||||
|
setAutoRefresh(true);
|
||||||
|
return;
|
||||||
case DownloadManagerService.MESSAGE_ERROR:
|
case DownloadManagerService.MESSAGE_ERROR:
|
||||||
case DownloadManagerService.MESSAGE_FINISHED:
|
case DownloadManagerService.MESSAGE_FINISHED:
|
||||||
break;
|
break;
|
||||||
|
@ -339,8 +341,6 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
if (msg.what == DownloadManagerService.MESSAGE_FINISHED) {
|
if (msg.what == DownloadManagerService.MESSAGE_FINISHED) {
|
||||||
// DownloadManager should mark the download as finished
|
// DownloadManager should mark the download as finished
|
||||||
applyChanges();
|
applyChanges();
|
||||||
|
|
||||||
mPendingDownloadsItems.remove(i);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +396,9 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (mission.errCode >= 100 && mission.errCode < 600) {
|
if (mission.errCode >= 100 && mission.errCode < 600) {
|
||||||
str.append("HTTP");
|
str = new StringBuilder(8);
|
||||||
|
str.append("HTTP ");
|
||||||
|
str.append(mission.errCode);
|
||||||
} else if (mission.errObject == null) {
|
} else if (mission.errObject == null) {
|
||||||
str.append("(not_decelerated_error_code)");
|
str.append("(not_decelerated_error_code)");
|
||||||
}
|
}
|
||||||
|
@ -436,7 +438,7 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
case R.id.pause:
|
case R.id.pause:
|
||||||
h.state = -1;
|
h.state = -1;
|
||||||
mDownloadManager.pauseMission(mission);
|
mDownloadManager.pauseMission(mission);
|
||||||
notifyItemChanged(h.getAdapterPosition());
|
updateProgress(h);
|
||||||
h.lastTimeStamp = -1;
|
h.lastTimeStamp = -1;
|
||||||
h.lastDone = -1;
|
h.lastDone = -1;
|
||||||
return true;
|
return true;
|
||||||
|
@ -542,6 +544,43 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean mUpdaterRunning = false;
|
||||||
|
private final Runnable rUpdater = this::updater;
|
||||||
|
|
||||||
|
public void onPaused() {
|
||||||
|
setAutoRefresh(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setAutoRefresh(boolean enabled) {
|
||||||
|
if (enabled && !mUpdaterRunning) {
|
||||||
|
mUpdaterRunning = true;
|
||||||
|
updater();
|
||||||
|
} else if (!enabled && mUpdaterRunning) {
|
||||||
|
mUpdaterRunning = false;
|
||||||
|
mHandler.removeCallbacks(rUpdater);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updater() {
|
||||||
|
if (!mUpdaterRunning) return;
|
||||||
|
|
||||||
|
boolean running = false;
|
||||||
|
for (ViewHolderItem h : mPendingDownloadsItems) {
|
||||||
|
// check if the mission is running first
|
||||||
|
if (!((DownloadMission) h.item.mission).running) continue;
|
||||||
|
|
||||||
|
updateProgress(h);
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (running) {
|
||||||
|
mHandler.postDelayed(rUpdater, 1000);
|
||||||
|
} else {
|
||||||
|
mUpdaterRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ViewHolderItem extends RecyclerView.ViewHolder {
|
class ViewHolderItem extends RecyclerView.ViewHolder {
|
||||||
DownloadManager.MissionItem item;
|
DownloadManager.MissionItem item;
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class MissionsFragment extends Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||||
mBinder = (DownloadManagerService.DMBinder) binder;
|
mBinder = (DownloadManagerService.DMBinder) binder;
|
||||||
mBinder.resetFinishedDownloadCount();
|
mBinder.clearDownloadNotifications();
|
||||||
|
|
||||||
mAdapter = new MissionAdapter(mActivity, mBinder.getDownloadManager(), mClear, mEmpty);
|
mAdapter = new MissionAdapter(mActivity, mBinder.getDownloadManager(), mClear, mEmpty);
|
||||||
mAdapter.deleterLoad(mBundle, getView());
|
mAdapter.deleterLoad(mBundle, getView());
|
||||||
|
@ -59,6 +59,7 @@ public class MissionsFragment extends Fragment {
|
||||||
mBundle = null;
|
mBundle = null;
|
||||||
|
|
||||||
mBinder.addMissionEventListener(mAdapter.getMessenger());
|
mBinder.addMissionEventListener(mAdapter.getMessenger());
|
||||||
|
mBinder.enableNotifications(false);
|
||||||
|
|
||||||
updateList();
|
updateList();
|
||||||
}
|
}
|
||||||
|
@ -141,6 +142,7 @@ public class MissionsFragment extends Fragment {
|
||||||
if (mBinder == null || mAdapter == null) return;
|
if (mBinder == null || mAdapter == null) return;
|
||||||
|
|
||||||
mBinder.removeMissionEventListener(mAdapter.getMessenger());
|
mBinder.removeMissionEventListener(mAdapter.getMessenger());
|
||||||
|
mBinder.enableNotifications(true);
|
||||||
mActivity.unbindService(mConnection);
|
mActivity.unbindService(mConnection);
|
||||||
mAdapter.deleterDispose(null);
|
mAdapter.deleterDispose(null);
|
||||||
|
|
||||||
|
@ -201,7 +203,6 @@ public class MissionsFragment extends Fragment {
|
||||||
mAdapter.deleterDispose(outState);
|
mAdapter.deleterDispose(outState);
|
||||||
mForceUpdate = true;
|
mForceUpdate = true;
|
||||||
mBinder.removeMissionEventListener(mAdapter.getMessenger());
|
mBinder.removeMissionEventListener(mAdapter.getMessenger());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,5 +220,13 @@ public class MissionsFragment extends Fragment {
|
||||||
|
|
||||||
mBinder.addMissionEventListener(mAdapter.getMessenger());
|
mBinder.addMissionEventListener(mAdapter.getMessenger());
|
||||||
}
|
}
|
||||||
|
if (mBinder != null) mBinder.enableNotifications(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
if (mAdapter != null) mAdapter.onPaused();
|
||||||
|
if (mBinder != null) mBinder.enableNotifications(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,7 +176,9 @@
|
||||||
<string name="default_file_charset_value" translatable="false">@string/charset_most_special_characters_value</string>
|
<string name="default_file_charset_value" translatable="false">@string/charset_most_special_characters_value</string>
|
||||||
|
|
||||||
<string name="downloads_max_retry" translatable="false">downloads_max_retry</string>
|
<string name="downloads_max_retry" translatable="false">downloads_max_retry</string>
|
||||||
|
<string name="downloads_max_retry_default" translatable="false">3</string>
|
||||||
<string-array name="downloads_max_retry_list" translatable="false">
|
<string-array name="downloads_max_retry_list" translatable="false">
|
||||||
|
<item translatable="true">@string/minimize_on_exit_none_description</item>
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
<item>2</item>
|
<item>2</item>
|
||||||
<item>3</item>
|
<item>3</item>
|
||||||
|
@ -187,8 +189,7 @@
|
||||||
<item>15</item>
|
<item>15</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="default_max_retry" translatable="false">3</string>
|
<string name="downloads_cross_network" translatable="false">cross_network_downloads</string>
|
||||||
<string name="cross_network_downloads" translatable="false">cross_network_downloads</string>
|
|
||||||
|
|
||||||
<string name="default_download_threads" translatable="false">default_download_threads</string>
|
<string name="default_download_threads" translatable="false">default_download_threads</string>
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
android:title="@string/settings_file_replacement_character_title"/>
|
android:title="@string/settings_file_replacement_character_title"/>
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="@string/default_max_retry"
|
android:defaultValue="@string/downloads_max_retry_default"
|
||||||
android:entries="@array/downloads_max_retry_list"
|
android:entries="@array/downloads_max_retry_list"
|
||||||
android:entryValues="@array/downloads_max_retry_list"
|
android:entryValues="@array/downloads_max_retry_list"
|
||||||
android:key="@string/downloads_max_retry"
|
android:key="@string/downloads_max_retry"
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="@string/cross_network_downloads"
|
android:key="@string/downloads_cross_network"
|
||||||
android:summary="@string/pause_downloads_on_mobile_desc"
|
android:summary="@string/pause_downloads_on_mobile_desc"
|
||||||
android:title="@string/pause_downloads_on_mobile" />
|
android:title="@string/pause_downloads_on_mobile" />
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue