فهرست منبع

Hold a wake lock until downloads are finished

inorichi 9 سال پیش
والد
کامیت
a130506514

+ 30 - 13
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<Page> downloadChapter(Download download) {
+    private Observable<Boolean> 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;
+    }
+
 }

+ 37 - 4
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();
+        }
+    }
+
 }