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:
kapodamy 2018-11-24 00:14:37 -03:00
parent d647555e3a
commit f3d4d4747a
12 changed files with 111 additions and 52 deletions

View file

@ -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;
}
}

View file

@ -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;

View 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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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() {

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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>

View file

@ -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"