From a13050651446e9ab9e07478b3d81a3a421370a33 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sat, 7 Nov 2015 22:10:08 +0100 Subject: [PATCH] Hold a wake lock until downloads are finished --- .../data/helpers/DownloadManager.java | 43 +++++++++++++------ .../data/services/DownloadService.java | 41 ++++++++++++++++-- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java b/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java index 1c5267cda9..087eec65c8 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java @@ -28,6 +28,7 @@ import eu.kanade.mangafeed.util.DiskUtils; import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator; import rx.Observable; import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; import rx.subjects.BehaviorSubject; import rx.subjects.PublishSubject; @@ -46,7 +47,8 @@ public class DownloadManager { private Subscription threadsNumberSubscription; private DownloadQueue queue; - private transient boolean isQueuePaused; + private volatile boolean isQueuePaused; + private volatile boolean isRunning; public static final String PAGE_LIST_FILE = "index.json"; @@ -54,9 +56,12 @@ public class DownloadManager { this.context = context; this.sourceManager = sourceManager; this.preferences = preferences; - this.gson = new Gson(); + gson = new Gson(); queue = new DownloadQueue(); + + downloadsQueueSubject = PublishSubject.create(); + threadsNumber = BehaviorSubject.create(); } public void initializeSubscriptions() { @@ -66,9 +71,6 @@ public class DownloadManager { if (threadsNumberSubscription != null && !threadsNumberSubscription.isUnsubscribed()) threadsNumberSubscription.unsubscribe(); - downloadsQueueSubject = PublishSubject.create(); - threadsNumber = BehaviorSubject.create(); - threadsNumberSubscription = preferences.getDownloadTheadsObservable() .filter(n -> !isQueuePaused) .doOnNext(n -> isQueuePaused = (n == 0)) @@ -78,11 +80,19 @@ public class DownloadManager { .observeOn(Schedulers.newThread()) .lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber)) .onBackpressureBuffer() - .subscribe(page -> {}, - e -> Timber.e(e.fillInStackTrace(), e.getMessage())); + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(finished -> { + if (finished) { + DownloadService.stop(context); + } + }, e -> Timber.e(e.fillInStackTrace(), e.getMessage())); + + isRunning = true; } public void destroySubscriptions() { + isRunning = false; + if (downloadsSubscription != null && !downloadsSubscription.isUnsubscribed()) { downloadsSubscription.unsubscribe(); downloadsSubscription = null; @@ -104,6 +114,7 @@ public class DownloadManager { if (!isChapterDownloaded(download)) { queue.add(download); + if (isRunning) downloadsQueueSubject.onNext(download); } } } @@ -139,7 +150,7 @@ public class DownloadManager { } // Download the entire chapter - private Observable downloadChapter(Download download) { + private Observable downloadChapter(Download download) { try { DiskUtils.createDirectory(download.directory); } catch (IOException e) { @@ -164,7 +175,9 @@ public class DownloadManager { // Start downloading images, consider we can have downloaded images already .concatMap(page -> getDownloadedImage(page, download.source, download.directory)) // 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 @@ -229,9 +242,6 @@ public class DownloadManager { private void onDownloadCompleted(final Download download) { checkDownloadIsSuccessful(download); savePageList(download); - if (areAllDownloadsFinished()) { - DownloadService.stop(context); - } } private void checkDownloadIsSuccessful(final Download download) { @@ -336,20 +346,27 @@ public class DownloadManager { threadsNumber.onNext(0); } - public void startDownloads() { + public boolean startDownloads() { + boolean hasPendingDownloads = false; if (downloadsSubscription == null || threadsNumberSubscription == null) initializeSubscriptions(); for (Download download : queue.get()) { if (download.getStatus() != Download.DOWNLOADED) { download.setStatus(Download.QUEUE); + if (!hasPendingDownloads) hasPendingDownloads = true; downloadsQueueSubject.onNext(download); } } + return hasPendingDownloads; } public void stopDownloads() { destroySubscriptions(); } + public boolean isRunning() { + return isRunning; + } + } diff --git a/app/src/main/java/eu/kanade/mangafeed/data/services/DownloadService.java b/app/src/main/java/eu/kanade/mangafeed/data/services/DownloadService.java index 272c53b5ff..730acda6e3 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/services/DownloadService.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/services/DownloadService.java @@ -6,6 +6,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.os.IBinder; +import android.os.PowerManager; import javax.inject.Inject; @@ -22,6 +23,7 @@ public class DownloadService extends Service { @Inject DownloadManager downloadManager; + private PowerManager.WakeLock wakeLock; private Subscription networkChangeSubscription; public static void start(Context context) { @@ -37,11 +39,10 @@ public class DownloadService extends Service { super.onCreate(); App.get(this).getComponent().inject(this); - // An initial event will be fired when subscribed. - // This will cause the following download events to start or wait for a connection - listenNetworkChanges(); + createWakeLock(); EventBus.getDefault().registerSticky(this); + listenNetworkChanges(); } @Override @@ -54,6 +55,7 @@ public class DownloadService extends Service { EventBus.getDefault().unregister(this); networkChangeSubscription.unsubscribe(); downloadManager.destroySubscriptions(); + destroyWakeLock(); super.onDestroy(); } @@ -66,6 +68,8 @@ public class DownloadService extends Service { public void onEvent(DownloadChaptersEvent event) { EventBus.getDefault().removeStickyEvent(event); downloadManager.onDownloadChaptersEvent(event); + if (downloadManager.isRunning()) + acquireWakeLock(); } private void listenNetworkChanges() { @@ -73,11 +77,40 @@ public class DownloadService extends Service { networkChangeSubscription = ContentObservable.fromBroadcast(this, intentFilter) .subscribe(state -> { if (NetworkUtil.isNetworkConnected(this)) { - downloadManager.startDownloads(); + // If there are no remaining downloads, destroy the service + if (!downloadManager.startDownloads()) + stopSelf(); + else + acquireWakeLock(); } else { 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(); + } + } + }