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
12 changed files with 111 additions and 52 deletions
|
@ -404,11 +404,26 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck
|
|||
|
||||
private int getSubtitleIndexBy(List<SubtitlesStream> streams) {
|
||||
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 i = 0; i < streams.size(); i++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,9 @@ public class DownloadInitializer implements Runnable {
|
|||
HttpURLConnection conn = mMission.openConnection(mId, -1, -1);
|
||||
if (!mMission.running || Thread.interrupted()) return;
|
||||
|
||||
mMission.length = conn.getContentLength();
|
||||
mMission.length = Utility.getContentLength(conn);
|
||||
|
||||
|
||||
if (mMission.length == 0) {
|
||||
mMission.notifyError(DownloadMission.ERROR_HTTP_NO_CONTENT, null);
|
||||
return;
|
||||
|
@ -97,7 +99,7 @@ public class DownloadInitializer implements Runnable {
|
|||
|
||||
for (long i = 0; i < mMission.currentThreadCount; i++) {
|
||||
mMission.threadBlockPositions.add(i);
|
||||
mMission.threadBytePositions.add(0);
|
||||
mMission.threadBytePositions.add(0L);
|
||||
}
|
||||
|
||||
File file;
|
||||
|
|
|
@ -124,7 +124,7 @@ public class DownloadMission extends Mission {
|
|||
@SuppressWarnings("UseSparseArrays")// LongSparseArray is not serializable
|
||||
private final HashMap<Long, Boolean> blockState = new HashMap<>();
|
||||
final List<Long> threadBlockPositions = new ArrayList<>();
|
||||
final List<Integer> threadBytePositions = new ArrayList<>();
|
||||
final List<Long> threadBytePositions = new ArrayList<>();
|
||||
|
||||
private transient boolean deleted;
|
||||
int currentThreadCount;
|
||||
|
@ -216,7 +216,7 @@ public class DownloadMission extends Mission {
|
|||
* @param threadId the identifier of the thread
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ public class DownloadMission extends Mission {
|
|||
* @param threadId the identifier of the thread
|
||||
* @return the relative position in bytes or zero
|
||||
*/
|
||||
int getBlockBytePosition(int threadId) {
|
||||
long getBlockBytePosition(int threadId) {
|
||||
return threadBytePositions.get(threadId);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ public class DownloadRunnable implements Runnable {
|
|||
end = mMission.length - 1;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
long total = 0;
|
||||
|
||||
try {
|
||||
HttpURLConnection conn = mMission.openConnection(mId, start, end);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package us.shandian.giga.get;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -10,9 +11,13 @@ import java.net.HttpURLConnection;
|
|||
import java.nio.channels.ClosedByInterruptException;
|
||||
|
||||
|
||||
import us.shandian.giga.util.Utility;
|
||||
|
||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||
|
||||
// Single-threaded fallback mode
|
||||
/**
|
||||
* Single-threaded fallback mode
|
||||
*/
|
||||
public class DownloadRunnableFallback implements Runnable {
|
||||
private static final String TAG = "DownloadRunnableFallback";
|
||||
|
||||
|
@ -43,10 +48,11 @@ public class DownloadRunnableFallback implements Runnable {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("LongLogTag")
|
||||
public void run() {
|
||||
boolean done;
|
||||
|
||||
int start = 0;
|
||||
long start = 0;
|
||||
|
||||
if (!mMission.unknownLength) {
|
||||
start = mMission.getBlockBytePosition(0);
|
||||
|
@ -56,11 +62,12 @@ public class DownloadRunnableFallback implements Runnable {
|
|||
}
|
||||
|
||||
try {
|
||||
int rangeStart = (mMission.unknownLength || start < 1) ? -1 : start;
|
||||
long 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;
|
||||
if (!mMission.unknownLength)
|
||||
mMission.unknownLength = Utility.getContentLength(conn) == -1;
|
||||
|
||||
f = new RandomAccessFile(mMission.getDownloadedFile(), "rw");
|
||||
f.seek(mMission.offsets[mMission.current] + start);
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package us.shandian.giga.service;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.util.DiffUtil;
|
||||
|
@ -46,9 +44,8 @@ public class DownloadManager {
|
|||
|
||||
private NetworkState mLastNetworkStatus = NetworkState.Unavailable;
|
||||
|
||||
private SharedPreferences mPrefs;
|
||||
private String mPrefMaxRetry;
|
||||
private String mPrefCrossNetwork;
|
||||
int mPrefMaxRetry;
|
||||
boolean mPrefCrossNetwork;
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
|
@ -65,9 +62,6 @@ public class DownloadManager {
|
|||
mHandler = handler;
|
||||
mMissionsFinished = loadFinishedMissions();
|
||||
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)) {
|
||||
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 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 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 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,
|
||||
String postprocessingName, String[] postProcessingArgs, long nearLength) {
|
||||
void startMission(String[] urls, String location, String name, char kind, int threads,
|
||||
String source, String psName, String[] psArgs, long nearLength) {
|
||||
synchronized (this) {
|
||||
// check for existing pending download
|
||||
DownloadMission pendingMission = getPendingMission(location, name);
|
||||
|
@ -225,12 +219,12 @@ public class DownloadManager {
|
|||
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.threadCount = threads;
|
||||
mission.source = source;
|
||||
mission.mHandler = mHandler;
|
||||
mission.maxRetry = mPrefs.getInt(mPrefMaxRetry, 3);
|
||||
mission.maxRetry = mPrefMaxRetry;
|
||||
mission.nearLength = nearLength;
|
||||
|
||||
while (true) {
|
||||
|
@ -420,6 +414,7 @@ public class DownloadManager {
|
|||
|
||||
/**
|
||||
* runs another mission in queue if possible
|
||||
*
|
||||
* @return true if exits pending missions running or a mission was started, otherwise, false
|
||||
*/
|
||||
boolean runAnotherMission() {
|
||||
|
@ -460,18 +455,17 @@ public class DownloadManager {
|
|||
|
||||
private boolean canDownloadInCurrentNetwork() {
|
||||
if (mLastNetworkStatus == NetworkState.Unavailable) return false;
|
||||
return !(mPrefs.getBoolean(mPrefCrossNetwork, false) && mLastNetworkStatus == NetworkState.MobileOperating);
|
||||
return !(mPrefCrossNetwork && mLastNetworkStatus == NetworkState.MobileOperating);
|
||||
}
|
||||
|
||||
void handleConnectivityChange(NetworkState currentStatus) {
|
||||
if (currentStatus == mLastNetworkStatus) return;
|
||||
|
||||
mLastNetworkStatus = currentStatus;
|
||||
boolean pauseOnMobile = mPrefs.getBoolean(mPrefCrossNetwork, false);
|
||||
|
||||
if (currentStatus == NetworkState.Unavailable) {
|
||||
return;
|
||||
} else if (currentStatus != NetworkState.MobileOperating || !pauseOnMobile) {
|
||||
} else if (currentStatus != NetworkState.MobileOperating || !mPrefCrossNetwork) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -488,9 +482,9 @@ public class DownloadManager {
|
|||
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
}
|
||||
|
||||
void updateMaximumAttempts(int maxRetry) {
|
||||
void updateMaximumAttempts() {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
private void updateProgress(ViewHolderItem h) {
|
||||
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;
|
||||
h.progress.setProgress(0f);
|
||||
} else {
|
||||
progress = (float) mission.done / mission.length;
|
||||
progress = (float) ((double) mission.done / mission.length);
|
||||
if (mission.urls.length > 1 && mission.current < mission.urls.length) {
|
||||
progress = (progress / mission.urls.length) + ((float) mission.current / mission.urls.length);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
} else if (Float.isNaN(progress) || Float.isInfinite(progress)) {
|
||||
h.status.setText("--.-%");
|
||||
|
@ -275,7 +277,7 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
|||
|
||||
|
||||
if (deltaTime > 1000 && deltaDone > 0) {
|
||||
float speed = (float) deltaDone / deltaTime;
|
||||
float speed = (float) ((double) deltaDone / deltaTime);
|
||||
String speedStr = Utility.formatSpeed(speed * 1000);
|
||||
String sizeStr = Utility.formatBytes(length);
|
||||
|
||||
|
@ -497,7 +499,7 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
|||
mIterator.start();
|
||||
mIterator.end();
|
||||
|
||||
for (ViewHolderItem item: mPendingDownloadsItems) {
|
||||
for (ViewHolderItem item : mPendingDownloadsItems) {
|
||||
item.lastTimeStamp = -1;
|
||||
}
|
||||
|
||||
|
@ -592,11 +594,9 @@ public class MissionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
|||
checksum = menu.findItem(R.id.checksum);
|
||||
|
||||
itemView.setOnClickListener((v) -> {
|
||||
if (((DownloadMission) item.mission).isFinished())
|
||||
if (item.mission instanceof FinishedMission)
|
||||
viewWithFileProvider(item.mission.getDownloadedFile());
|
||||
});
|
||||
|
||||
//h.itemView.setOnClickListener(v -> showDetail(h));
|
||||
}
|
||||
|
||||
private void showPopupMenu() {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package us.shandian.giga.ui.common;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.design.widget.Snackbar;
|
||||
|
@ -11,6 +13,7 @@ import org.schabi.newpipe.R;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import us.shandian.giga.get.FinishedMission;
|
||||
import us.shandian.giga.get.Mission;
|
||||
import us.shandian.giga.service.DownloadManager;
|
||||
import us.shandian.giga.service.DownloadManager.MissionIterator;
|
||||
|
@ -120,6 +123,10 @@ public class Deleter {
|
|||
|
||||
mIterator.unHide(mission);
|
||||
mDownloadManager.deleteMission(mission);
|
||||
|
||||
if (mission instanceof FinishedMission) {
|
||||
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(mission.getDownloadedFile())));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package us.shandian.giga.util;
|
|||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.NonNull;
|
||||
|
@ -21,6 +22,7 @@ import java.io.IOException;
|
|||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Locale;
|
||||
|
@ -38,11 +40,11 @@ public class Utility {
|
|||
if (bytes < 1024) {
|
||||
return String.format("%d B", bytes);
|
||||
} 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) {
|
||||
return String.format("%.2f MB", (float) bytes / 1024 / 1024);
|
||||
return String.format("%.2f MB", bytes / 1024d / 1024d);
|
||||
} 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();
|
||||
}
|
||||
|
||||
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="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="cross_network_downloads" translatable="false">cross_network_downloads</string>
|
||||
|
||||
|
|
|
@ -29,14 +29,15 @@
|
|||
android:summary="@string/settings_file_replacement_character_summary"
|
||||
android:title="@string/settings_file_replacement_character_title"/>
|
||||
|
||||
<SeekBarPreference
|
||||
<ListPreference
|
||||
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:max="15"
|
||||
android:summary="@string/max_retry_desc"
|
||||
android:title="@string/max_retry_msg" />
|
||||
|
||||
<CheckBoxPreference
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/cross_network_downloads"
|
||||
android:summary="@string/pause_downloads_on_mobile_desc"
|
||||
|
|
Loading…
Reference in a new issue