and more fixes
* fix content length reading * use float overflow. Expensive, double is used instead * fix invalid cast after click the mission body * use a list for maximum attemps (downloads) * minor clean up (DownloadManager.java) * dont pass SharedPreferences instace to DownloadManager * use a switch instead of checkbox for cross_network_downloads * notify media scanner after deleting a finished download
This commit is contained in:
parent
d647555e3a
commit
f3d4d4747a
|
@ -404,11 +404,26 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
||||||
|
|
||||||
private int getSubtitleIndexBy(List<SubtitlesStream> streams) {
|
private int getSubtitleIndexBy(List<SubtitlesStream> streams) {
|
||||||
Localization loc = NewPipe.getPreferredLocalization();
|
Localization loc = NewPipe.getPreferredLocalization();
|
||||||
|
|
||||||
|
for (int i = 0; i < streams.size(); i++) {
|
||||||
|
Locale streamLocale = streams.get(i).getLocale();
|
||||||
|
String tag = streamLocale.getLanguage().concat("-").concat(streamLocale.getCountry());
|
||||||
|
if (tag.equalsIgnoreCase(loc.getLanguage())) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
// 1st loop match country & language
|
||||||
|
// 2nd loop match language only
|
||||||
|
String lang = loc.getLanguage().substring(0, loc.getLanguage().indexOf("-"));
|
||||||
|
|
||||||
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++) {
|
||||||
Locale streamLocale = streams.get(i).getLocale();
|
Locale streamLocale = streams.get(i).getLocale();
|
||||||
if (streamLocale.getLanguage().equals(loc.getLanguage())) {
|
|
||||||
if (j > 0 || streamLocale.getCountry().equals(loc.getCountry())) {
|
if (streamLocale.getLanguage().equalsIgnoreCase(lang)) {
|
||||||
|
if (j > 0 || streamLocale.getCountry().equalsIgnoreCase(loc.getCountry())) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,9 @@ public class DownloadInitializer implements Runnable {
|
||||||
HttpURLConnection conn = mMission.openConnection(mId, -1, -1);
|
HttpURLConnection conn = mMission.openConnection(mId, -1, -1);
|
||||||
if (!mMission.running || Thread.interrupted()) return;
|
if (!mMission.running || Thread.interrupted()) return;
|
||||||
|
|
||||||
mMission.length = conn.getContentLength();
|
mMission.length = Utility.getContentLength(conn);
|
||||||
|
|
||||||
|
|
||||||
if (mMission.length == 0) {
|
if (mMission.length == 0) {
|
||||||
mMission.notifyError(DownloadMission.ERROR_HTTP_NO_CONTENT, null);
|
mMission.notifyError(DownloadMission.ERROR_HTTP_NO_CONTENT, null);
|
||||||
return;
|
return;
|
||||||
|
@ -97,7 +99,7 @@ public class DownloadInitializer implements Runnable {
|
||||||
|
|
||||||
for (long i = 0; i < mMission.currentThreadCount; i++) {
|
for (long i = 0; i < mMission.currentThreadCount; i++) {
|
||||||
mMission.threadBlockPositions.add(i);
|
mMission.threadBlockPositions.add(i);
|
||||||
mMission.threadBytePositions.add(0);
|
mMission.threadBytePositions.add(0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
File file;
|
File file;
|
||||||
|
|
|
@ -124,7 +124,7 @@ public class DownloadMission extends Mission {
|
||||||
@SuppressWarnings("UseSparseArrays")// LongSparseArray is not serializable
|
@SuppressWarnings("UseSparseArrays")// LongSparseArray is not serializable
|
||||||
private final HashMap<Long, Boolean> blockState = new HashMap<>();
|
private final HashMap<Long, Boolean> blockState = new HashMap<>();
|
||||||
final List<Long> threadBlockPositions = new ArrayList<>();
|
final List<Long> threadBlockPositions = new ArrayList<>();
|
||||||
final List<Integer> threadBytePositions = new ArrayList<>();
|
final List<Long> threadBytePositions = new ArrayList<>();
|
||||||
|
|
||||||
private transient boolean deleted;
|
private transient boolean deleted;
|
||||||
int currentThreadCount;
|
int currentThreadCount;
|
||||||
|
@ -216,7 +216,7 @@ public class DownloadMission extends Mission {
|
||||||
* @param threadId the identifier of the thread
|
* @param threadId the identifier of the thread
|
||||||
* @param position the relative position in bytes or zero
|
* @param position the relative position in bytes or zero
|
||||||
*/
|
*/
|
||||||
void setThreadBytePosition(int threadId, int position) {
|
void setThreadBytePosition(int threadId, long position) {
|
||||||
threadBytePositions.set(threadId, position);
|
threadBytePositions.set(threadId, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ public class DownloadMission extends Mission {
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
int getBlockBytePosition(int threadId) {
|
long getBlockBytePosition(int threadId) {
|
||||||
return threadBytePositions.get(threadId);
|
return threadBytePositions.get(threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class DownloadRunnable implements Runnable {
|
||||||
end = mMission.length - 1;
|
end = mMission.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int total = 0;
|
long total = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpURLConnection conn = mMission.openConnection(mId, start, end);
|
HttpURLConnection conn = mMission.openConnection(mId, start, end);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package us.shandian.giga.get;
|
package us.shandian.giga.get;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
@ -10,9 +11,13 @@ import java.net.HttpURLConnection;
|
||||||
import java.nio.channels.ClosedByInterruptException;
|
import java.nio.channels.ClosedByInterruptException;
|
||||||
|
|
||||||
|
|
||||||
|
import us.shandian.giga.util.Utility;
|
||||||
|
|
||||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||||
|
|
||||||
// Single-threaded fallback mode
|
/**
|
||||||
|
* Single-threaded fallback mode
|
||||||
|
*/
|
||||||
public class DownloadRunnableFallback implements Runnable {
|
public class DownloadRunnableFallback implements Runnable {
|
||||||
private static final String TAG = "DownloadRunnableFallback";
|
private static final String TAG = "DownloadRunnableFallback";
|
||||||
|
|
||||||
|
@ -43,10 +48,11 @@ public class DownloadRunnableFallback implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressLint("LongLogTag")
|
||||||
public void run() {
|
public void run() {
|
||||||
boolean done;
|
boolean done;
|
||||||
|
|
||||||
int start = 0;
|
long start = 0;
|
||||||
|
|
||||||
if (!mMission.unknownLength) {
|
if (!mMission.unknownLength) {
|
||||||
start = mMission.getBlockBytePosition(0);
|
start = mMission.getBlockBytePosition(0);
|
||||||
|
@ -56,11 +62,12 @@ public class DownloadRunnableFallback implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int rangeStart = (mMission.unknownLength || start < 1) ? -1 : start;
|
long rangeStart = (mMission.unknownLength || start < 1) ? -1 : start;
|
||||||
HttpURLConnection conn = mMission.openConnection(1, rangeStart, -1);
|
HttpURLConnection conn = mMission.openConnection(1, rangeStart, -1);
|
||||||
|
|
||||||
// secondary check for the file length
|
// secondary check for the file length
|
||||||
if (!mMission.unknownLength) mMission.unknownLength = conn.getContentLength() == -1;
|
if (!mMission.unknownLength)
|
||||||
|
mMission.unknownLength = Utility.getContentLength(conn) == -1;
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package us.shandian.giga.service;
|
package us.shandian.giga.service;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.util.DiffUtil;
|
import android.support.v7.util.DiffUtil;
|
||||||
|
@ -46,9 +44,8 @@ public class DownloadManager {
|
||||||
|
|
||||||
private NetworkState mLastNetworkStatus = NetworkState.Unavailable;
|
private NetworkState mLastNetworkStatus = NetworkState.Unavailable;
|
||||||
|
|
||||||
private SharedPreferences mPrefs;
|
int mPrefMaxRetry;
|
||||||
private String mPrefMaxRetry;
|
boolean mPrefCrossNetwork;
|
||||||
private String mPrefCrossNetwork;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance
|
* Create a new instance
|
||||||
|
@ -65,9 +62,6 @@ public class DownloadManager {
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mMissionsFinished = loadFinishedMissions();
|
mMissionsFinished = loadFinishedMissions();
|
||||||
mPendingMissionsDir = getPendingDir(context);
|
mPendingMissionsDir = getPendingDir(context);
|
||||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
mPrefMaxRetry = context.getString(R.string.downloads_max_retry);
|
|
||||||
mPrefCrossNetwork = context.getString(R.string.cross_network_downloads);
|
|
||||||
|
|
||||||
if (!Utility.mkdir(mPendingMissionsDir, false)) {
|
if (!Utility.mkdir(mPendingMissionsDir, false)) {
|
||||||
throw new RuntimeException("failed to create pending_downloads in data directory");
|
throw new RuntimeException("failed to create pending_downloads in data directory");
|
||||||
|
@ -201,12 +195,12 @@ public class DownloadManager {
|
||||||
* @param name the name of the file to create
|
* @param name the name of the file to create
|
||||||
* @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined)
|
* @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined)
|
||||||
* @param threads the number of threads maximal used to download chunks of the file.
|
* @param threads the number of threads maximal used to download chunks of the file.
|
||||||
* @param postprocessingName the name of the required post-processing algorithm, or {@code null} to ignore.
|
* @param psName the name of the required post-processing algorithm, or {@code null} to ignore.
|
||||||
* @param source source url of the resource
|
* @param source source url of the resource
|
||||||
* @param postProcessingArgs the arguments for the post-processing algorithm.
|
* @param psArgs the arguments for the post-processing algorithm.
|
||||||
*/
|
*/
|
||||||
void startMission(String[] urls, String location, String name, char kind, int threads, String source,
|
void startMission(String[] urls, String location, String name, char kind, int threads,
|
||||||
String postprocessingName, String[] postProcessingArgs, long nearLength) {
|
String source, String psName, String[] psArgs, long nearLength) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
// check for existing pending download
|
// check for existing pending download
|
||||||
DownloadMission pendingMission = getPendingMission(location, name);
|
DownloadMission pendingMission = getPendingMission(location, name);
|
||||||
|
@ -225,12 +219,12 @@ public class DownloadManager {
|
||||||
if (index >= 0) mDownloadDataSource.deleteMission(mMissionsFinished.remove(index));
|
if (index >= 0) mDownloadDataSource.deleteMission(mMissionsFinished.remove(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadMission mission = new DownloadMission(urls, name, location, kind, postprocessingName, postProcessingArgs);
|
DownloadMission mission = new DownloadMission(urls, name, location, kind, psName, psArgs);
|
||||||
mission.timestamp = System.currentTimeMillis();
|
mission.timestamp = System.currentTimeMillis();
|
||||||
mission.threadCount = threads;
|
mission.threadCount = threads;
|
||||||
mission.source = source;
|
mission.source = source;
|
||||||
mission.mHandler = mHandler;
|
mission.mHandler = mHandler;
|
||||||
mission.maxRetry = mPrefs.getInt(mPrefMaxRetry, 3);
|
mission.maxRetry = mPrefMaxRetry;
|
||||||
mission.nearLength = nearLength;
|
mission.nearLength = nearLength;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -420,6 +414,7 @@ public class DownloadManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* runs another mission in queue if possible
|
* runs another mission in queue if possible
|
||||||
|
*
|
||||||
* @return true if exits pending missions running or a mission was started, otherwise, false
|
* @return true if exits pending missions running or a mission was started, otherwise, false
|
||||||
*/
|
*/
|
||||||
boolean runAnotherMission() {
|
boolean runAnotherMission() {
|
||||||
|
@ -460,18 +455,17 @@ public class DownloadManager {
|
||||||
|
|
||||||
private boolean canDownloadInCurrentNetwork() {
|
private boolean canDownloadInCurrentNetwork() {
|
||||||
if (mLastNetworkStatus == NetworkState.Unavailable) return false;
|
if (mLastNetworkStatus == NetworkState.Unavailable) return false;
|
||||||
return !(mPrefs.getBoolean(mPrefCrossNetwork, false) && mLastNetworkStatus == NetworkState.MobileOperating);
|
return !(mPrefCrossNetwork && mLastNetworkStatus == NetworkState.MobileOperating);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleConnectivityChange(NetworkState currentStatus) {
|
void handleConnectivityChange(NetworkState currentStatus) {
|
||||||
if (currentStatus == mLastNetworkStatus) return;
|
if (currentStatus == mLastNetworkStatus) return;
|
||||||
|
|
||||||
mLastNetworkStatus = currentStatus;
|
mLastNetworkStatus = currentStatus;
|
||||||
boolean pauseOnMobile = mPrefs.getBoolean(mPrefCrossNetwork, false);
|
|
||||||
|
|
||||||
if (currentStatus == NetworkState.Unavailable) {
|
if (currentStatus == NetworkState.Unavailable) {
|
||||||
return;
|
return;
|
||||||
} else if (currentStatus != NetworkState.MobileOperating || !pauseOnMobile) {
|
} else if (currentStatus != NetworkState.MobileOperating || !mPrefCrossNetwork) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,9 +482,9 @@ public class DownloadManager {
|
||||||
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateMaximumAttempts(int maxRetry) {
|
void updateMaximumAttempts() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
for (DownloadMission mission : mMissionsPending) mission.maxRetry = maxRetry;
|
for (DownloadMission mission : mMissionsPending) mission.maxRetry = mPrefMaxRetry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -306,7 +306,12 @@ 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.updateMaximumAttempts(prefs.getInt(key, 3));
|
mManager.mPrefMaxRetry = Integer.parseInt(
|
||||||
|
prefs.getString(key, getString(R.string.default_max_retry))
|
||||||
|
);
|
||||||
|
mManager.updateMaximumAttempts();
|
||||||
|
} else if (key.equals(getString(R.string.cross_network_downloads))) {
|
||||||
|
mManager.mPrefCrossNetwork = prefs.getBoolean(key, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,7 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
return mIterator.getSpecialAtItem(position);
|
return mIterator.getSpecialAtItem(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
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;
|
||||||
|
|
||||||
|
@ -216,14 +217,15 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
progress = Float.NaN;
|
progress = Float.NaN;
|
||||||
h.progress.setProgress(0f);
|
h.progress.setProgress(0f);
|
||||||
} else {
|
} else {
|
||||||
progress = (float) 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)) h.progress.setProgress(1f);
|
if (Float.isNaN(progress) || Float.isInfinite(progress))
|
||||||
|
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("--.-%");
|
||||||
|
@ -275,7 +277,7 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
|
|
||||||
|
|
||||||
if (deltaTime > 1000 && deltaDone > 0) {
|
if (deltaTime > 1000 && deltaDone > 0) {
|
||||||
float speed = (float) deltaDone / deltaTime;
|
float speed = (float) ((double) deltaDone / deltaTime);
|
||||||
String speedStr = Utility.formatSpeed(speed * 1000);
|
String speedStr = Utility.formatSpeed(speed * 1000);
|
||||||
String sizeStr = Utility.formatBytes(length);
|
String sizeStr = Utility.formatBytes(length);
|
||||||
|
|
||||||
|
@ -592,11 +594,9 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||||
checksum = menu.findItem(R.id.checksum);
|
checksum = menu.findItem(R.id.checksum);
|
||||||
|
|
||||||
itemView.setOnClickListener((v) -> {
|
itemView.setOnClickListener((v) -> {
|
||||||
if (((DownloadMission) item.mission).isFinished())
|
if (item.mission instanceof FinishedMission)
|
||||||
viewWithFileProvider(item.mission.getDownloadedFile());
|
viewWithFileProvider(item.mission.getDownloadedFile());
|
||||||
});
|
});
|
||||||
|
|
||||||
//h.itemView.setOnClickListener(v -> showDetail(h));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPopupMenu() {
|
private void showPopupMenu() {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package us.shandian.giga.ui.common;
|
package us.shandian.giga.ui.common;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
|
@ -11,6 +13,7 @@ import org.schabi.newpipe.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import us.shandian.giga.get.FinishedMission;
|
||||||
import us.shandian.giga.get.Mission;
|
import us.shandian.giga.get.Mission;
|
||||||
import us.shandian.giga.service.DownloadManager;
|
import us.shandian.giga.service.DownloadManager;
|
||||||
import us.shandian.giga.service.DownloadManager.MissionIterator;
|
import us.shandian.giga.service.DownloadManager.MissionIterator;
|
||||||
|
@ -120,6 +123,10 @@ public class Deleter {
|
||||||
|
|
||||||
mIterator.unHide(mission);
|
mIterator.unHide(mission);
|
||||||
mDownloadManager.deleteMission(mission);
|
mDownloadManager.deleteMission(mission);
|
||||||
|
|
||||||
|
if (mission instanceof FinishedMission) {
|
||||||
|
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(mission.getDownloadedFile())));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package us.shandian.giga.util;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
import android.support.annotation.ColorInt;
|
import android.support.annotation.ColorInt;
|
||||||
import android.support.annotation.DrawableRes;
|
import android.support.annotation.DrawableRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -21,6 +22,7 @@ import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -38,11 +40,11 @@ public class Utility {
|
||||||
if (bytes < 1024) {
|
if (bytes < 1024) {
|
||||||
return String.format("%d B", bytes);
|
return String.format("%d B", bytes);
|
||||||
} else if (bytes < 1024 * 1024) {
|
} else if (bytes < 1024 * 1024) {
|
||||||
return String.format("%.2f kB", (float) bytes / 1024);
|
return String.format("%.2f kB", bytes / 1024d);
|
||||||
} else if (bytes < 1024 * 1024 * 1024) {
|
} else if (bytes < 1024 * 1024 * 1024) {
|
||||||
return String.format("%.2f MB", (float) bytes / 1024 / 1024);
|
return String.format("%.2f MB", bytes / 1024d / 1024d);
|
||||||
} else {
|
} else {
|
||||||
return String.format("%.2f GB", (float) bytes / 1024 / 1024 / 1024);
|
return String.format("%.2f GB", bytes / 1024d / 1024d / 1024d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,4 +257,19 @@ public class Utility {
|
||||||
|
|
||||||
return path.exists();
|
return path.exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long getContentLength(HttpURLConnection connection) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
return connection.getContentLengthLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
long length = Long.parseLong(connection.getHeaderField("Content-Length"));
|
||||||
|
if (length >= 0) return length;
|
||||||
|
} catch (Exception err) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,6 +176,17 @@
|
||||||
<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-array name="downloads_max_retry_list" translatable="false">
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
<item>4</item>
|
||||||
|
<item>5</item>
|
||||||
|
<item>7</item>
|
||||||
|
<item>10</item>
|
||||||
|
<item>15</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string name="default_max_retry" translatable="false">3</string>
|
<string name="default_max_retry" translatable="false">3</string>
|
||||||
<string name="cross_network_downloads" translatable="false">cross_network_downloads</string>
|
<string name="cross_network_downloads" translatable="false">cross_network_downloads</string>
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,15 @@
|
||||||
android:summary="@string/settings_file_replacement_character_summary"
|
android:summary="@string/settings_file_replacement_character_summary"
|
||||||
android:title="@string/settings_file_replacement_character_title"/>
|
android:title="@string/settings_file_replacement_character_title"/>
|
||||||
|
|
||||||
<SeekBarPreference
|
<ListPreference
|
||||||
android:defaultValue="@string/default_max_retry"
|
android:defaultValue="@string/default_max_retry"
|
||||||
|
android:entries="@array/downloads_max_retry_list"
|
||||||
|
android:entryValues="@array/downloads_max_retry_list"
|
||||||
android:key="@string/downloads_max_retry"
|
android:key="@string/downloads_max_retry"
|
||||||
android:max="15"
|
|
||||||
android:summary="@string/max_retry_desc"
|
android:summary="@string/max_retry_desc"
|
||||||
android:title="@string/max_retry_msg" />
|
android:title="@string/max_retry_msg" />
|
||||||
|
|
||||||
<CheckBoxPreference
|
<SwitchPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="@string/cross_network_downloads"
|
android:key="@string/cross_network_downloads"
|
||||||
android:summary="@string/pause_downloads_on_mobile_desc"
|
android:summary="@string/pause_downloads_on_mobile_desc"
|
||||||
|
|
Loading…
Reference in New Issue