New MP4 muxer + Queue changes + Storage fixes
Main changes: * correctly check the available space (CircularFile.java) * misc cleanup (CircularFile.java) * use the "Error Reporter" for non-http errors * rewrite network state checking and add better support for API 21 (Lollipop) or higher * implement "metered networks" * add buttons in "Downloads" activity to start/pause all pending downloads, ignoring the queue flag or if the network is "metered" * add workaround for VPN connections and/or network switching. Example: switching WiFi to 3G * rewrite DataReader ¡Webm muxer is now 57% more faster! * rewrite CircularFile, use file buffers instead of memory buffers. Less troubles in low-end devices * fix missing offset for KaxCluster (WebMWriter.java), manifested as no thumbnails on file explorers Download queue: * remember queue status, unless the user pause the download (un-queue) * semi-automatic downloads, between networks. Effective if the user create a new download or the downloads activity is starts * allow enqueue failed downloads * new option, queue limit, enabled by default. Used to allow one or multiple downloads at same time Miscellaneous: * fix crash while selecting details/error menu (mistake on MissionFragment.java) * misc serialize changes (DownloadMission.java) * minor UI tweaks * allow overwrite paused downloads * fix wrong icons for grid/list button in downloads * add share option * implement #2006 * correct misspelled word in strings.xml (es) (cmn) * fix MissionAdapter crash during device shutdown New Mp4Muxer + required changes: * new mp4 muxer (from dash only) with this, muxing on Android 7 is possible now!!! * re-work in SharpStream * drop mp4 dash muxer * misc changes: add warning in SecondaryStreamHelper.java, * strip m4a DASH files to normal m4a format (youtube only) Fix storage issues: * warn to the user if is choosing a "read only" download directory (for external SD Cards), useless is rooted :) * "write proof" allow post-processing resuming only if the device ran out of space * implement "insufficient storage" error for downloads
This commit is contained in:
parent
b19caad970
commit
8d8059229f
49 changed files with 2715 additions and 1936 deletions
|
|
@ -21,6 +21,8 @@ import us.shandian.giga.get.DownloadMission;
|
|||
import us.shandian.giga.get.FinishedMission;
|
||||
import us.shandian.giga.get.Mission;
|
||||
import us.shandian.giga.get.sqlite.DownloadDataSource;
|
||||
import us.shandian.giga.service.DownloadManagerService.DMChecker;
|
||||
import us.shandian.giga.service.DownloadManagerService.MissionCheck;
|
||||
import us.shandian.giga.util.Utility;
|
||||
|
||||
import static org.schabi.newpipe.BuildConfig.DEBUG;
|
||||
|
|
@ -28,7 +30,7 @@ import static org.schabi.newpipe.BuildConfig.DEBUG;
|
|||
public class DownloadManager {
|
||||
private static final String TAG = DownloadManager.class.getSimpleName();
|
||||
|
||||
enum NetworkState {Unavailable, WifiOperating, MobileOperating, OtherOperating}
|
||||
enum NetworkState {Unavailable, Operating, MeteredOperating}
|
||||
|
||||
public final static int SPECIAL_NOTHING = 0;
|
||||
public final static int SPECIAL_PENDING = 1;
|
||||
|
|
@ -45,7 +47,9 @@ public class DownloadManager {
|
|||
private NetworkState mLastNetworkStatus = NetworkState.Unavailable;
|
||||
|
||||
int mPrefMaxRetry;
|
||||
boolean mPrefCrossNetwork;
|
||||
boolean mPrefMeteredDownloads;
|
||||
boolean mPrefQueueLimit;
|
||||
private boolean mSelfMissionsControl;
|
||||
|
||||
/**
|
||||
* Create a new instance
|
||||
|
|
@ -152,8 +156,8 @@ public class DownloadManager {
|
|||
}
|
||||
|
||||
mis.postprocessingState = 0;
|
||||
mis.errCode = DownloadMission.ERROR_POSTPROCESSING;
|
||||
mis.errObject = new RuntimeException("stopped unexpectedly");
|
||||
mis.errCode = DownloadMission.ERROR_POSTPROCESSING_STOPPED;
|
||||
mis.errObject = null;
|
||||
} else if (exists && !dl.isFile()) {
|
||||
// probably a folder, this should never happens
|
||||
if (!sub.delete()) {
|
||||
|
|
@ -162,20 +166,21 @@ public class DownloadManager {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
if (!exists && mis.isInitialized()) {
|
||||
// downloaded file deleted, reset mission state
|
||||
DownloadMission m = new DownloadMission(mis.urls, mis.name, mis.location, mis.kind, mis.postprocessingName, mis.postprocessingArgs);
|
||||
m.timestamp = mis.timestamp;
|
||||
m.threadCount = mis.threadCount;
|
||||
m.source = mis.source;
|
||||
m.maxRetry = mis.maxRetry;
|
||||
m.nearLength = mis.nearLength;
|
||||
m.setEnqueued(mis.enqueued);
|
||||
mis = m;
|
||||
}
|
||||
|
||||
mis.running = false;
|
||||
mis.recovered = exists;
|
||||
mis.metadata = sub;
|
||||
mis.maxRetry = mPrefMaxRetry;
|
||||
mis.mHandler = mHandler;
|
||||
|
||||
mMissionsPending.add(mis);
|
||||
|
|
@ -205,17 +210,25 @@ public class DownloadManager {
|
|||
synchronized (this) {
|
||||
// check for existing pending download
|
||||
DownloadMission pendingMission = getPendingMission(location, name);
|
||||
|
||||
if (pendingMission != null) {
|
||||
// generate unique filename (?)
|
||||
try {
|
||||
name = generateUniqueName(location, name);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to generate unique name", e);
|
||||
name = System.currentTimeMillis() + name;
|
||||
Log.i(TAG, "Using " + name);
|
||||
if (pendingMission.running) {
|
||||
// generate unique filename (?)
|
||||
try {
|
||||
name = generateUniqueName(location, name);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to generate unique name", e);
|
||||
name = System.currentTimeMillis() + name;
|
||||
Log.i(TAG, "Using " + name);
|
||||
}
|
||||
} else {
|
||||
// dispose the mission
|
||||
mMissionsPending.remove(pendingMission);
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_DELETED);
|
||||
pendingMission.delete();
|
||||
}
|
||||
} else {
|
||||
// check for existing finished download
|
||||
// check for existing finished download and dispose (if exists)
|
||||
int index = getFinishedMissionIndex(location, name);
|
||||
if (index >= 0) mDownloadDataSource.deleteMission(mMissionsFinished.remove(index));
|
||||
}
|
||||
|
|
@ -242,14 +255,17 @@ public class DownloadManager {
|
|||
mission.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
mSelfMissionsControl = true;
|
||||
mMissionsPending.add(mission);
|
||||
|
||||
// Before starting, save the state in case the internet connection is not available
|
||||
// Before continue, save the metadata in case the internet connection is not available
|
||||
Utility.writeToFile(mission.metadata, mission);
|
||||
|
||||
if (canDownloadInCurrentNetwork() && (getRunningMissionsCount() < 1)) {
|
||||
boolean start = !mPrefQueueLimit || getRunningMissionsCount() < 1;
|
||||
|
||||
if (canDownloadInCurrentNetwork() && start) {
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PROGRESS);
|
||||
mission.start();
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_RUNNING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -257,13 +273,14 @@ public class DownloadManager {
|
|||
|
||||
public void resumeMission(DownloadMission mission) {
|
||||
if (!mission.running) {
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PROGRESS);
|
||||
mission.start();
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
public void pauseMission(DownloadMission mission) {
|
||||
if (mission.running) {
|
||||
mission.setEnqueued(false);
|
||||
mission.pause();
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
}
|
||||
|
|
@ -335,7 +352,7 @@ public class DownloadManager {
|
|||
int count = 0;
|
||||
synchronized (this) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (mission.running && !mission.isFinished() && !mission.isPsFailed())
|
||||
if (mission.running && !mission.isPsFailed() && !mission.isFinished())
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
|
@ -343,10 +360,36 @@ public class DownloadManager {
|
|||
return count;
|
||||
}
|
||||
|
||||
void pauseAllMissions() {
|
||||
public void pauseAllMissions(boolean force) {
|
||||
boolean flag = false;
|
||||
|
||||
synchronized (this) {
|
||||
for (DownloadMission mission : mMissionsPending) mission.pause();
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (!mission.running || mission.isPsRunning() || mission.isFinished()) continue;
|
||||
|
||||
if (force) mission.threads = null;// avoid waiting for threads
|
||||
|
||||
mission.pause();
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
}
|
||||
|
||||
public void startAllMissions() {
|
||||
boolean flag = false;
|
||||
|
||||
synchronized (this) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (mission.running || mission.isPsFailed() || mission.isFinished()) continue;
|
||||
|
||||
flag = true;
|
||||
mission.start();
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PROGRESS);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -415,31 +458,35 @@ public class DownloadManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* runs another mission in queue if possible
|
||||
* runs one or multiple missions in from queue if possible
|
||||
*
|
||||
* @return true if exits pending missions running or a mission was started, otherwise, false
|
||||
* @return true if one or multiple missions are running, otherwise, false
|
||||
*/
|
||||
boolean runAnotherMission() {
|
||||
boolean runMissions() {
|
||||
synchronized (this) {
|
||||
if (mMissionsPending.size() < 1) return false;
|
||||
|
||||
int i = getRunningMissionsCount();
|
||||
if (i > 0) return true;
|
||||
|
||||
if (!canDownloadInCurrentNetwork()) return false;
|
||||
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (!mission.running && mission.errCode == DownloadMission.ERROR_NOTHING && mission.enqueued) {
|
||||
resumeMission(mission);
|
||||
return true;
|
||||
}
|
||||
if (mPrefQueueLimit) {
|
||||
for (DownloadMission mission : mMissionsPending)
|
||||
if (!mission.isFinished() && mission.running) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
boolean flag = false;
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (mission.running || !mission.enqueued || mission.isFinished()) continue;
|
||||
|
||||
resumeMission(mission);
|
||||
if (mPrefQueueLimit) return true;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
public MissionIterator getIterator() {
|
||||
mSelfMissionsControl = true;
|
||||
return new MissionIterator();
|
||||
}
|
||||
|
||||
|
|
@ -457,31 +504,43 @@ public class DownloadManager {
|
|||
|
||||
private boolean canDownloadInCurrentNetwork() {
|
||||
if (mLastNetworkStatus == NetworkState.Unavailable) return false;
|
||||
return !(mPrefCrossNetwork && mLastNetworkStatus == NetworkState.MobileOperating);
|
||||
return !(mPrefMeteredDownloads && mLastNetworkStatus == NetworkState.MeteredOperating);
|
||||
}
|
||||
|
||||
void handleConnectivityChange(NetworkState currentStatus) {
|
||||
void handleConnectivityState(NetworkState currentStatus, boolean updateOnly) {
|
||||
if (currentStatus == mLastNetworkStatus) return;
|
||||
|
||||
mLastNetworkStatus = currentStatus;
|
||||
if (currentStatus == NetworkState.Unavailable) return;
|
||||
|
||||
if (currentStatus == NetworkState.Unavailable) {
|
||||
return;
|
||||
} else if (currentStatus != NetworkState.MobileOperating || !mPrefCrossNetwork) {
|
||||
return;
|
||||
if (!mSelfMissionsControl || updateOnly) {
|
||||
return;// don't touch anything without the user interaction
|
||||
}
|
||||
|
||||
boolean flag = false;
|
||||
boolean isMetered = mPrefMeteredDownloads && mLastNetworkStatus == NetworkState.MeteredOperating;
|
||||
|
||||
int running = 0;
|
||||
int paused = 0;
|
||||
synchronized (this) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (mission.running && !mission.isFinished() && !mission.isPsRunning()) {
|
||||
flag = true;
|
||||
if (mission.isFinished() || mission.isPsRunning()) continue;
|
||||
|
||||
if (mission.running && isMetered) {
|
||||
paused++;
|
||||
mission.pause();
|
||||
} else if (!mission.running && !isMetered && mission.enqueued) {
|
||||
running++;
|
||||
mission.start();
|
||||
if (mPrefQueueLimit) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
if (running > 0) {
|
||||
mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PROGRESS);
|
||||
return;
|
||||
}
|
||||
if (paused > 0) mHandler.sendEmptyMessage(DownloadManagerService.MESSAGE_PAUSED);
|
||||
}
|
||||
|
||||
void updateMaximumAttempts() {
|
||||
|
|
@ -506,21 +565,24 @@ public class DownloadManager {
|
|||
), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
void checkForRunningMission(String location, String name, DownloadManagerService.DMChecker check) {
|
||||
boolean listed;
|
||||
boolean finished = false;
|
||||
void checkForRunningMission(String location, String name, DMChecker check) {
|
||||
MissionCheck result = MissionCheck.None;
|
||||
|
||||
synchronized (this) {
|
||||
DownloadMission mission = getPendingMission(location, name);
|
||||
if (mission != null) {
|
||||
listed = true;
|
||||
DownloadMission pending = getPendingMission(location, name);
|
||||
|
||||
if (pending == null) {
|
||||
if (getFinishedMissionIndex(location, name) >= 0) result = MissionCheck.Finished;
|
||||
} else {
|
||||
listed = getFinishedMissionIndex(location, name) >= 0;
|
||||
finished = listed;
|
||||
if (pending.isFinished()) {
|
||||
result = MissionCheck.Finished;// this never should happen (race-condition)
|
||||
} else {
|
||||
result = pending.running ? MissionCheck.PendingRunning : MissionCheck.Pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check.callback(listed, finished);
|
||||
check.callback(result);
|
||||
}
|
||||
|
||||
public class MissionIterator extends DiffUtil.Callback {
|
||||
|
|
@ -592,39 +654,6 @@ public class DownloadManager {
|
|||
return SPECIAL_NOTHING;
|
||||
}
|
||||
|
||||
public MissionItem getItemUnsafe(int position) {
|
||||
synchronized (DownloadManager.this) {
|
||||
int count = mMissionsPending.size();
|
||||
int count2 = mMissionsFinished.size();
|
||||
|
||||
if (count > 0) {
|
||||
position--;
|
||||
if (position == -1)
|
||||
return new MissionItem(SPECIAL_PENDING);
|
||||
else if (position < count)
|
||||
return new MissionItem(SPECIAL_NOTHING, mMissionsPending.get(position));
|
||||
else if (position == count && count2 > 0)
|
||||
return new MissionItem(SPECIAL_FINISHED);
|
||||
else
|
||||
position -= count;
|
||||
} else {
|
||||
if (count2 > 0 && position == 0) {
|
||||
return new MissionItem(SPECIAL_FINISHED);
|
||||
}
|
||||
}
|
||||
|
||||
position--;
|
||||
|
||||
if (count2 < 1) {
|
||||
throw new RuntimeException(
|
||||
String.format("Out of range. pending_count=%s finished_count=%s position=%s", count, count2, position)
|
||||
);
|
||||
}
|
||||
|
||||
return new MissionItem(SPECIAL_NOTHING, mMissionsFinished.get(position));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void start() {
|
||||
current = getSpecialItems();
|
||||
|
|
@ -647,6 +676,32 @@ public class DownloadManager {
|
|||
return hasFinished;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if exists missions running and paused. Corrupted and hidden missions are not counted
|
||||
*
|
||||
* @return two-dimensional array contains the current missions state.
|
||||
* 1° entry: true if has at least one mission running
|
||||
* 2° entry: true if has at least one mission paused
|
||||
*/
|
||||
public boolean[] hasValidPendingMissions() {
|
||||
boolean running = false;
|
||||
boolean paused = false;
|
||||
|
||||
synchronized (DownloadManager.this) {
|
||||
for (DownloadMission mission : mMissionsPending) {
|
||||
if (hidden.contains(mission) || mission.isPsFailed() || mission.isFinished())
|
||||
continue;
|
||||
|
||||
if (mission.running)
|
||||
paused = true;
|
||||
else
|
||||
running = true;
|
||||
}
|
||||
}
|
||||
|
||||
return new boolean[]{running, paused};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getOldListSize() {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ import android.content.SharedPreferences;
|
|||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
|
|
@ -24,6 +26,7 @@ import android.os.IBinder;
|
|||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationCompat.Builder;
|
||||
import android.support.v4.content.PermissionChecker;
|
||||
|
|
@ -48,7 +51,6 @@ public class DownloadManagerService extends Service {
|
|||
|
||||
private static final String TAG = "DownloadManagerService";
|
||||
|
||||
public static final int MESSAGE_RUNNING = 0;
|
||||
public static final int MESSAGE_PAUSED = 1;
|
||||
public static final int MESSAGE_FINISHED = 2;
|
||||
public static final int MESSAGE_PROGRESS = 3;
|
||||
|
|
@ -76,7 +78,7 @@ public class DownloadManagerService extends Service {
|
|||
private Notification mNotification;
|
||||
private Handler mHandler;
|
||||
private boolean mForeground = false;
|
||||
private NotificationManager notificationManager = null;
|
||||
private NotificationManager mNotificationManager = null;
|
||||
private boolean mDownloadNotificationEnable = true;
|
||||
|
||||
private int downloadDoneCount = 0;
|
||||
|
|
@ -85,7 +87,9 @@ public class DownloadManagerService extends Service {
|
|||
|
||||
private final ArrayList<Handler> mEchoObservers = new ArrayList<>(1);
|
||||
|
||||
private BroadcastReceiver mNetworkStateListener;
|
||||
private ConnectivityManager mConnectivityManager;
|
||||
private BroadcastReceiver mNetworkStateListener = null;
|
||||
private ConnectivityManager.NetworkCallback mNetworkStateListenerL = null;
|
||||
|
||||
private SharedPreferences mPrefs = null;
|
||||
private final SharedPreferences.OnSharedPreferenceChangeListener mPrefChangeListener = this::handlePreferenceChange;
|
||||
|
|
@ -147,25 +151,39 @@ public class DownloadManagerService extends Service {
|
|||
.setContentText(getString(R.string.msg_running_detail));
|
||||
|
||||
mNotification = builder.build();
|
||||
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
mNetworkStateListener = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
|
||||
handleConnectivityChange(null);
|
||||
return;
|
||||
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
mNetworkStateListenerL = new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
handleConnectivityState(false);
|
||||
}
|
||||
handleConnectivityChange(intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO));
|
||||
}
|
||||
};
|
||||
registerReceiver(mNetworkStateListener, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
handleConnectivityState(false);
|
||||
}
|
||||
};
|
||||
mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder().build(), mNetworkStateListenerL);
|
||||
} else {
|
||||
mNetworkStateListener = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
handleConnectivityState(false);
|
||||
}
|
||||
};
|
||||
registerReceiver(mNetworkStateListener, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
}
|
||||
|
||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
mPrefs.registerOnSharedPreferenceChangeListener(mPrefChangeListener);
|
||||
|
||||
handlePreferenceChange(mPrefs, getString(R.string.downloads_cross_network));
|
||||
handlePreferenceChange(mPrefs, getString(R.string.downloads_maximum_retry));
|
||||
handlePreferenceChange(mPrefs, getString(R.string.downloads_queue_limit));
|
||||
|
||||
mLock = new LockManager(this);
|
||||
}
|
||||
|
|
@ -173,12 +191,11 @@ public class DownloadManagerService extends Service {
|
|||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (DEBUG) {
|
||||
if (intent == null) {
|
||||
Log.d(TAG, "Restarting");
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
Log.d(TAG, "Starting");
|
||||
Log.d(TAG, intent == null ? "Restarting" : "Starting");
|
||||
}
|
||||
|
||||
if (intent == null) return START_NOT_STICKY;
|
||||
|
||||
Log.i(TAG, "Got intent: " + intent);
|
||||
String action = intent.getAction();
|
||||
if (action != null) {
|
||||
|
|
@ -193,6 +210,8 @@ public class DownloadManagerService extends Service {
|
|||
String source = intent.getStringExtra(EXTRA_SOURCE);
|
||||
long nearLength = intent.getLongExtra(EXTRA_NEAR_LENGTH, 0);
|
||||
|
||||
handleConnectivityState(true);// first check the actual network status
|
||||
|
||||
mHandler.post(() -> mManager.startMission(urls, location, name, kind, threads, source, psName, psArgs, nearLength));
|
||||
|
||||
} else if (downloadDoneNotification != null) {
|
||||
|
|
@ -221,21 +240,25 @@ public class DownloadManagerService extends Service {
|
|||
|
||||
stopForeground(true);
|
||||
|
||||
if (notificationManager != null && downloadDoneNotification != null) {
|
||||
if (mNotificationManager != null && downloadDoneNotification != null) {
|
||||
downloadDoneNotification.setDeleteIntent(null);// prevent NewPipe running when is killed, cleared from recent, etc
|
||||
notificationManager.notify(DOWNLOADS_NOTIFICATION_ID, downloadDoneNotification.build());
|
||||
mNotificationManager.notify(DOWNLOADS_NOTIFICATION_ID, downloadDoneNotification.build());
|
||||
}
|
||||
|
||||
mManager.pauseAllMissions();
|
||||
|
||||
manageLock(false);
|
||||
|
||||
unregisterReceiver(mNetworkStateListener);
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
mConnectivityManager.unregisterNetworkCallback(mNetworkStateListenerL);
|
||||
else
|
||||
unregisterReceiver(mNetworkStateListener);
|
||||
|
||||
mPrefs.unregisterOnSharedPreferenceChangeListener(mPrefChangeListener);
|
||||
|
||||
if (icDownloadDone != null) icDownloadDone.recycle();
|
||||
if (icDownloadFailed != null) icDownloadFailed.recycle();
|
||||
if (icLauncher != null) icLauncher.recycle();
|
||||
|
||||
mManager.pauseAllMissions(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -264,15 +287,16 @@ public class DownloadManagerService extends Service {
|
|||
notifyMediaScanner(mission.getDownloadedFile());
|
||||
notifyFinishedDownload(mission.name);
|
||||
mManager.setFinished(mission);
|
||||
updateForegroundState(mManager.runAnotherMission());
|
||||
handleConnectivityState(false);
|
||||
updateForegroundState(mManager.runMissions());
|
||||
break;
|
||||
case MESSAGE_RUNNING:
|
||||
case MESSAGE_PROGRESS:
|
||||
updateForegroundState(true);
|
||||
break;
|
||||
case MESSAGE_ERROR:
|
||||
notifyFailedDownload(mission);
|
||||
updateForegroundState(mManager.runAnotherMission());
|
||||
handleConnectivityState(false);
|
||||
updateForegroundState(mManager.runMissions());
|
||||
break;
|
||||
case MESSAGE_PAUSED:
|
||||
updateForegroundState(mManager.getRunningMissionsCount() > 0);
|
||||
|
|
@ -293,36 +317,30 @@ public class DownloadManagerService extends Service {
|
|||
}
|
||||
}
|
||||
|
||||
private void handleConnectivityChange(NetworkInfo info) {
|
||||
private void handleConnectivityState(boolean updateOnly) {
|
||||
NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
|
||||
NetworkState status;
|
||||
|
||||
if (info == null) {
|
||||
status = NetworkState.Unavailable;
|
||||
Log.i(TAG, "actual connectivity status is unavailable");
|
||||
} else if (!info.isAvailable() || !info.isConnected()) {
|
||||
status = NetworkState.Unavailable;
|
||||
Log.i(TAG, "actual connectivity status is not available and not connected");
|
||||
Log.i(TAG, "Active network [connectivity is unavailable]");
|
||||
} else {
|
||||
int type = info.getType();
|
||||
if (type == ConnectivityManager.TYPE_MOBILE || type == ConnectivityManager.TYPE_MOBILE_DUN) {
|
||||
status = NetworkState.MobileOperating;
|
||||
} else if (type == ConnectivityManager.TYPE_WIFI) {
|
||||
status = NetworkState.WifiOperating;
|
||||
} else if (type == ConnectivityManager.TYPE_WIMAX ||
|
||||
type == ConnectivityManager.TYPE_ETHERNET ||
|
||||
type == ConnectivityManager.TYPE_BLUETOOTH) {
|
||||
status = NetworkState.OtherOperating;
|
||||
} else {
|
||||
boolean connected = info.isConnected();
|
||||
boolean metered = mConnectivityManager.isActiveNetworkMetered();
|
||||
|
||||
if (connected)
|
||||
status = metered ? NetworkState.MeteredOperating : NetworkState.Operating;
|
||||
else
|
||||
status = NetworkState.Unavailable;
|
||||
}
|
||||
Log.i(TAG, "actual connectivity status is " + status.name());
|
||||
|
||||
Log.i(TAG, "Active network [connected=" + connected + " metered=" + metered + "] " + info.toString());
|
||||
}
|
||||
|
||||
if (mManager == null) return;// avoid race-conditions while the service is starting
|
||||
mManager.handleConnectivityChange(status);
|
||||
mManager.handleConnectivityState(status, updateOnly);
|
||||
}
|
||||
|
||||
private void handlePreferenceChange(SharedPreferences prefs, String key) {
|
||||
private void handlePreferenceChange(SharedPreferences prefs, @NonNull String key) {
|
||||
if (key.equals(getString(R.string.downloads_maximum_retry))) {
|
||||
try {
|
||||
String value = prefs.getString(key, getString(R.string.downloads_maximum_retry_default));
|
||||
|
|
@ -332,7 +350,9 @@ public class DownloadManagerService extends Service {
|
|||
}
|
||||
mManager.updateMaximumAttempts();
|
||||
} else if (key.equals(getString(R.string.downloads_cross_network))) {
|
||||
mManager.mPrefCrossNetwork = prefs.getBoolean(key, false);
|
||||
mManager.mPrefMeteredDownloads = prefs.getBoolean(key, false);
|
||||
} else if (key.equals(getString(R.string.downloads_queue_limit))) {
|
||||
mManager.mPrefQueueLimit = prefs.getBoolean(key, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -366,19 +386,20 @@ public class DownloadManagerService extends Service {
|
|||
context.startService(intent);
|
||||
}
|
||||
|
||||
public static void checkForRunningMission(Context context, String location, String name, DMChecker check) {
|
||||
public static void checkForRunningMission(Context context, String location, String name, DMChecker checker) {
|
||||
Intent intent = new Intent();
|
||||
intent.setClass(context, DownloadManagerService.class);
|
||||
context.startService(intent);
|
||||
|
||||
context.bindService(intent, new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName cname, IBinder service) {
|
||||
try {
|
||||
((DMBinder) service).getDownloadManager().checkForRunningMission(location, name, check);
|
||||
((DMBinder) service).getDownloadManager().checkForRunningMission(location, name, checker);
|
||||
} catch (Exception err) {
|
||||
Log.w(TAG, "checkForRunningMission() callback is defective", err);
|
||||
}
|
||||
|
||||
// TODO: find a efficient way to unbind the service. This destroy the service due idle, but is started again when the user start a download.
|
||||
context.unbindService(this);
|
||||
}
|
||||
|
||||
|
|
@ -389,7 +410,7 @@ public class DownloadManagerService extends Service {
|
|||
}
|
||||
|
||||
public void notifyFinishedDownload(String name) {
|
||||
if (!mDownloadNotificationEnable || notificationManager == null) {
|
||||
if (!mDownloadNotificationEnable || mNotificationManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +449,7 @@ public class DownloadManagerService extends Service {
|
|||
downloadDoneNotification.setContentText(downloadDoneList);
|
||||
}
|
||||
|
||||
notificationManager.notify(DOWNLOADS_NOTIFICATION_ID, downloadDoneNotification.build());
|
||||
mNotificationManager.notify(DOWNLOADS_NOTIFICATION_ID, downloadDoneNotification.build());
|
||||
downloadDoneCount++;
|
||||
}
|
||||
|
||||
|
|
@ -458,7 +479,7 @@ public class DownloadManagerService extends Service {
|
|||
.bigText(mission.name));
|
||||
}
|
||||
|
||||
notificationManager.notify(id, downloadFailedNotification.build());
|
||||
mNotificationManager.notify(id, downloadFailedNotification.build());
|
||||
}
|
||||
|
||||
private PendingIntent makePendingIntent(String action) {
|
||||
|
|
@ -487,7 +508,11 @@ public class DownloadManagerService extends Service {
|
|||
mLockAcquired = acquire;
|
||||
}
|
||||
|
||||
// Wrapper of DownloadManager
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Wrappers for DownloadManager
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public class DMBinder extends Binder {
|
||||
public DownloadManager getDownloadManager() {
|
||||
return mManager;
|
||||
|
|
@ -502,15 +527,15 @@ public class DownloadManagerService extends Service {
|
|||
}
|
||||
|
||||
public void clearDownloadNotifications() {
|
||||
if (notificationManager == null) return;
|
||||
if (mNotificationManager == null) return;
|
||||
if (downloadDoneNotification != null) {
|
||||
notificationManager.cancel(DOWNLOADS_NOTIFICATION_ID);
|
||||
mNotificationManager.cancel(DOWNLOADS_NOTIFICATION_ID);
|
||||
downloadDoneList.setLength(0);
|
||||
downloadDoneCount = 0;
|
||||
}
|
||||
if (downloadFailedNotification != null) {
|
||||
for (; downloadFailedNotificationID > DOWNLOADS_NOTIFICATION_ID; downloadFailedNotificationID--) {
|
||||
notificationManager.cancel(downloadFailedNotificationID);
|
||||
mNotificationManager.cancel(downloadFailedNotificationID);
|
||||
}
|
||||
mFailedDownloads.clear();
|
||||
downloadFailedNotificationID++;
|
||||
|
|
@ -524,7 +549,9 @@ public class DownloadManagerService extends Service {
|
|||
}
|
||||
|
||||
public interface DMChecker {
|
||||
void callback(boolean listed, boolean finished);
|
||||
void callback(MissionCheck result);
|
||||
}
|
||||
|
||||
public enum MissionCheck {None, Pending, PendingRunning, Finished}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue