Hold a wake lock until downloads are finished
This commit is contained in:
parent
0f372ba069
commit
a130506514
2 changed files with 67 additions and 17 deletions
|
@ -28,6 +28,7 @@ import eu.kanade.mangafeed.util.DiskUtils;
|
||||||
import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator;
|
import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator;
|
||||||
import rx.Observable;
|
import rx.Observable;
|
||||||
import rx.Subscription;
|
import rx.Subscription;
|
||||||
|
import rx.android.schedulers.AndroidSchedulers;
|
||||||
import rx.schedulers.Schedulers;
|
import rx.schedulers.Schedulers;
|
||||||
import rx.subjects.BehaviorSubject;
|
import rx.subjects.BehaviorSubject;
|
||||||
import rx.subjects.PublishSubject;
|
import rx.subjects.PublishSubject;
|
||||||
|
@ -46,7 +47,8 @@ public class DownloadManager {
|
||||||
private Subscription threadsNumberSubscription;
|
private Subscription threadsNumberSubscription;
|
||||||
|
|
||||||
private DownloadQueue queue;
|
private DownloadQueue queue;
|
||||||
private transient boolean isQueuePaused;
|
private volatile boolean isQueuePaused;
|
||||||
|
private volatile boolean isRunning;
|
||||||
|
|
||||||
public static final String PAGE_LIST_FILE = "index.json";
|
public static final String PAGE_LIST_FILE = "index.json";
|
||||||
|
|
||||||
|
@ -54,9 +56,12 @@ public class DownloadManager {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.sourceManager = sourceManager;
|
this.sourceManager = sourceManager;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
this.gson = new Gson();
|
|
||||||
|
|
||||||
|
gson = new Gson();
|
||||||
queue = new DownloadQueue();
|
queue = new DownloadQueue();
|
||||||
|
|
||||||
|
downloadsQueueSubject = PublishSubject.create();
|
||||||
|
threadsNumber = BehaviorSubject.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initializeSubscriptions() {
|
public void initializeSubscriptions() {
|
||||||
|
@ -66,9 +71,6 @@ public class DownloadManager {
|
||||||
if (threadsNumberSubscription != null && !threadsNumberSubscription.isUnsubscribed())
|
if (threadsNumberSubscription != null && !threadsNumberSubscription.isUnsubscribed())
|
||||||
threadsNumberSubscription.unsubscribe();
|
threadsNumberSubscription.unsubscribe();
|
||||||
|
|
||||||
downloadsQueueSubject = PublishSubject.create();
|
|
||||||
threadsNumber = BehaviorSubject.create();
|
|
||||||
|
|
||||||
threadsNumberSubscription = preferences.getDownloadTheadsObservable()
|
threadsNumberSubscription = preferences.getDownloadTheadsObservable()
|
||||||
.filter(n -> !isQueuePaused)
|
.filter(n -> !isQueuePaused)
|
||||||
.doOnNext(n -> isQueuePaused = (n == 0))
|
.doOnNext(n -> isQueuePaused = (n == 0))
|
||||||
|
@ -78,11 +80,19 @@ public class DownloadManager {
|
||||||
.observeOn(Schedulers.newThread())
|
.observeOn(Schedulers.newThread())
|
||||||
.lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber))
|
.lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber))
|
||||||
.onBackpressureBuffer()
|
.onBackpressureBuffer()
|
||||||
.subscribe(page -> {},
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
e -> Timber.e(e.fillInStackTrace(), e.getMessage()));
|
.subscribe(finished -> {
|
||||||
|
if (finished) {
|
||||||
|
DownloadService.stop(context);
|
||||||
|
}
|
||||||
|
}, e -> Timber.e(e.fillInStackTrace(), e.getMessage()));
|
||||||
|
|
||||||
|
isRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroySubscriptions() {
|
public void destroySubscriptions() {
|
||||||
|
isRunning = false;
|
||||||
|
|
||||||
if (downloadsSubscription != null && !downloadsSubscription.isUnsubscribed()) {
|
if (downloadsSubscription != null && !downloadsSubscription.isUnsubscribed()) {
|
||||||
downloadsSubscription.unsubscribe();
|
downloadsSubscription.unsubscribe();
|
||||||
downloadsSubscription = null;
|
downloadsSubscription = null;
|
||||||
|
@ -104,6 +114,7 @@ public class DownloadManager {
|
||||||
|
|
||||||
if (!isChapterDownloaded(download)) {
|
if (!isChapterDownloaded(download)) {
|
||||||
queue.add(download);
|
queue.add(download);
|
||||||
|
if (isRunning) downloadsQueueSubject.onNext(download);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +150,7 @@ public class DownloadManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download the entire chapter
|
// Download the entire chapter
|
||||||
private Observable<Page> downloadChapter(Download download) {
|
private Observable<Boolean> downloadChapter(Download download) {
|
||||||
try {
|
try {
|
||||||
DiskUtils.createDirectory(download.directory);
|
DiskUtils.createDirectory(download.directory);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -164,7 +175,9 @@ public class DownloadManager {
|
||||||
// Start downloading images, consider we can have downloaded images already
|
// Start downloading images, consider we can have downloaded images already
|
||||||
.concatMap(page -> getDownloadedImage(page, download.source, download.directory))
|
.concatMap(page -> getDownloadedImage(page, download.source, download.directory))
|
||||||
// Do after download completes
|
// Do after download completes
|
||||||
.doOnCompleted(() -> onDownloadCompleted(download));
|
.doOnCompleted(() -> onDownloadCompleted(download))
|
||||||
|
.toList()
|
||||||
|
.flatMap(pages -> Observable.just(areAllDownloadsFinished()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get downloaded image if exists, otherwise download it with the method below
|
// Get downloaded image if exists, otherwise download it with the method below
|
||||||
|
@ -229,9 +242,6 @@ public class DownloadManager {
|
||||||
private void onDownloadCompleted(final Download download) {
|
private void onDownloadCompleted(final Download download) {
|
||||||
checkDownloadIsSuccessful(download);
|
checkDownloadIsSuccessful(download);
|
||||||
savePageList(download);
|
savePageList(download);
|
||||||
if (areAllDownloadsFinished()) {
|
|
||||||
DownloadService.stop(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDownloadIsSuccessful(final Download download) {
|
private void checkDownloadIsSuccessful(final Download download) {
|
||||||
|
@ -336,20 +346,27 @@ public class DownloadManager {
|
||||||
threadsNumber.onNext(0);
|
threadsNumber.onNext(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startDownloads() {
|
public boolean startDownloads() {
|
||||||
|
boolean hasPendingDownloads = false;
|
||||||
if (downloadsSubscription == null || threadsNumberSubscription == null)
|
if (downloadsSubscription == null || threadsNumberSubscription == null)
|
||||||
initializeSubscriptions();
|
initializeSubscriptions();
|
||||||
|
|
||||||
for (Download download : queue.get()) {
|
for (Download download : queue.get()) {
|
||||||
if (download.getStatus() != Download.DOWNLOADED) {
|
if (download.getStatus() != Download.DOWNLOADED) {
|
||||||
download.setStatus(Download.QUEUE);
|
download.setStatus(Download.QUEUE);
|
||||||
|
if (!hasPendingDownloads) hasPendingDownloads = true;
|
||||||
downloadsQueueSubject.onNext(download);
|
downloadsQueueSubject.onNext(download);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return hasPendingDownloads;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopDownloads() {
|
public void stopDownloads() {
|
||||||
destroySubscriptions();
|
destroySubscriptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return isRunning;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ public class DownloadService extends Service {
|
||||||
|
|
||||||
@Inject DownloadManager downloadManager;
|
@Inject DownloadManager downloadManager;
|
||||||
|
|
||||||
|
private PowerManager.WakeLock wakeLock;
|
||||||
private Subscription networkChangeSubscription;
|
private Subscription networkChangeSubscription;
|
||||||
|
|
||||||
public static void start(Context context) {
|
public static void start(Context context) {
|
||||||
|
@ -37,11 +39,10 @@ public class DownloadService extends Service {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
App.get(this).getComponent().inject(this);
|
App.get(this).getComponent().inject(this);
|
||||||
|
|
||||||
// An initial event will be fired when subscribed.
|
createWakeLock();
|
||||||
// This will cause the following download events to start or wait for a connection
|
|
||||||
listenNetworkChanges();
|
|
||||||
|
|
||||||
EventBus.getDefault().registerSticky(this);
|
EventBus.getDefault().registerSticky(this);
|
||||||
|
listenNetworkChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,6 +55,7 @@ public class DownloadService extends Service {
|
||||||
EventBus.getDefault().unregister(this);
|
EventBus.getDefault().unregister(this);
|
||||||
networkChangeSubscription.unsubscribe();
|
networkChangeSubscription.unsubscribe();
|
||||||
downloadManager.destroySubscriptions();
|
downloadManager.destroySubscriptions();
|
||||||
|
destroyWakeLock();
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +68,8 @@ public class DownloadService extends Service {
|
||||||
public void onEvent(DownloadChaptersEvent event) {
|
public void onEvent(DownloadChaptersEvent event) {
|
||||||
EventBus.getDefault().removeStickyEvent(event);
|
EventBus.getDefault().removeStickyEvent(event);
|
||||||
downloadManager.onDownloadChaptersEvent(event);
|
downloadManager.onDownloadChaptersEvent(event);
|
||||||
|
if (downloadManager.isRunning())
|
||||||
|
acquireWakeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void listenNetworkChanges() {
|
private void listenNetworkChanges() {
|
||||||
|
@ -73,11 +77,40 @@ public class DownloadService extends Service {
|
||||||
networkChangeSubscription = ContentObservable.fromBroadcast(this, intentFilter)
|
networkChangeSubscription = ContentObservable.fromBroadcast(this, intentFilter)
|
||||||
.subscribe(state -> {
|
.subscribe(state -> {
|
||||||
if (NetworkUtil.isNetworkConnected(this)) {
|
if (NetworkUtil.isNetworkConnected(this)) {
|
||||||
downloadManager.startDownloads();
|
// If there are no remaining downloads, destroy the service
|
||||||
|
if (!downloadManager.startDownloads())
|
||||||
|
stopSelf();
|
||||||
|
else
|
||||||
|
acquireWakeLock();
|
||||||
} else {
|
} else {
|
||||||
downloadManager.stopDownloads();
|
downloadManager.stopDownloads();
|
||||||
|
releaseWakeLock();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createWakeLock() {
|
||||||
|
wakeLock = ((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(
|
||||||
|
PowerManager.PARTIAL_WAKE_LOCK, "DownloadService:WakeLock");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroyWakeLock() {
|
||||||
|
if (wakeLock != null && wakeLock.isHeld()) {
|
||||||
|
wakeLock.release();
|
||||||
|
wakeLock = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acquireWakeLock() {
|
||||||
|
if (wakeLock != null && !wakeLock.isHeld()) {
|
||||||
|
wakeLock.acquire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void releaseWakeLock() {
|
||||||
|
if (wakeLock != null && wakeLock.isHeld()) {
|
||||||
|
wakeLock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue