Hold a wake lock until downloads are finished

This commit is contained in:
inorichi 2015-11-07 22:10:08 +01:00
parent 0f372ba069
commit a130506514
2 changed files with 67 additions and 17 deletions

View File

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

View File

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