LibraryUpdateService.java 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package eu.kanade.mangafeed.data.sync;
  2. import android.app.Service;
  3. import android.content.BroadcastReceiver;
  4. import android.content.Context;
  5. import android.content.Intent;
  6. import android.os.IBinder;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9. import java.util.concurrent.atomic.AtomicInteger;
  10. import javax.inject.Inject;
  11. import eu.kanade.mangafeed.App;
  12. import eu.kanade.mangafeed.BuildConfig;
  13. import eu.kanade.mangafeed.R;
  14. import eu.kanade.mangafeed.data.database.DatabaseHelper;
  15. import eu.kanade.mangafeed.data.database.models.Manga;
  16. import eu.kanade.mangafeed.data.source.SourceManager;
  17. import eu.kanade.mangafeed.util.AndroidComponentUtil;
  18. import eu.kanade.mangafeed.util.NetworkUtil;
  19. import eu.kanade.mangafeed.util.NotificationUtil;
  20. import eu.kanade.mangafeed.util.PostResult;
  21. import rx.Observable;
  22. import rx.Subscription;
  23. import rx.schedulers.Schedulers;
  24. import timber.log.Timber;
  25. public class LibraryUpdateService extends Service {
  26. @Inject DatabaseHelper db;
  27. @Inject SourceManager sourceManager;
  28. private Subscription updateSubscription;
  29. public static final int UPDATE_NOTIFICATION_ID = 1;
  30. public static Intent getStartIntent(Context context) {
  31. return new Intent(context, LibraryUpdateService.class);
  32. }
  33. public static boolean isRunning(Context context) {
  34. return AndroidComponentUtil.isServiceRunning(context, LibraryUpdateService.class);
  35. }
  36. @Override
  37. public void onCreate() {
  38. super.onCreate();
  39. App.get(this).getComponent().inject(this);
  40. }
  41. @Override
  42. public void onDestroy() {
  43. if (updateSubscription != null)
  44. updateSubscription.unsubscribe();
  45. super.onDestroy();
  46. }
  47. @Override
  48. public int onStartCommand(Intent intent, int flags, final int startId) {
  49. Timber.i("Starting sync...");
  50. if (!NetworkUtil.isNetworkConnected(this)) {
  51. Timber.i("Sync canceled, connection not available");
  52. AndroidComponentUtil.toggleComponent(this, SyncOnConnectionAvailable.class, true);
  53. stopSelf(startId);
  54. return START_NOT_STICKY;
  55. }
  56. Observable.fromCallable(() -> db.getFavoriteMangas().executeAsBlocking())
  57. .subscribeOn(Schedulers.io())
  58. .subscribe(mangas -> {
  59. startUpdating(mangas, startId);
  60. });
  61. return START_STICKY;
  62. }
  63. private void startUpdating(final List<Manga> mangas, final int startId) {
  64. final AtomicInteger count = new AtomicInteger(0);
  65. List<MangaUpdate> updates = new ArrayList<>();
  66. updateSubscription = Observable.from(mangas)
  67. .doOnNext(manga -> {
  68. NotificationUtil.create(this, UPDATE_NOTIFICATION_ID,
  69. getString(R.string.notification_progress,
  70. count.incrementAndGet(), mangas.size()), manga.title);
  71. })
  72. .concatMap(manga -> sourceManager.get(manga.source)
  73. .pullChaptersFromNetwork(manga.url)
  74. .flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters))
  75. .filter(result -> result.getNumberOfRowsInserted() > 0)
  76. .flatMap(result -> Observable.just(new MangaUpdate(manga, result))))
  77. .subscribe(update -> {
  78. updates.add(update);
  79. }, error -> {
  80. Timber.e("Error syncing");
  81. stopSelf(startId);
  82. }, () -> {
  83. NotificationUtil.createBigText(this, UPDATE_NOTIFICATION_ID,
  84. getString(R.string.notification_completed), getUpdatedMangas(updates));
  85. stopSelf(startId);
  86. });
  87. }
  88. private String getUpdatedMangas(List<MangaUpdate> updates) {
  89. final StringBuilder result = new StringBuilder();
  90. if (updates.isEmpty()) {
  91. result.append(getString(R.string.notification_no_new_chapters)).append("\n");
  92. } else {
  93. result.append(getString(R.string.notification_new_chapters));
  94. for (MangaUpdate update : updates) {
  95. result.append("\n").append(update.getManga().title);
  96. }
  97. }
  98. return result.toString();
  99. }
  100. @Override
  101. public IBinder onBind(Intent intent) {
  102. return null;
  103. }
  104. public static class SyncOnConnectionAvailable extends BroadcastReceiver {
  105. @Override
  106. public void onReceive(Context context, Intent intent) {
  107. if (NetworkUtil.isNetworkConnected(context)) {
  108. if (BuildConfig.DEBUG) {
  109. Timber.i("Connection is now available, triggering sync...");
  110. }
  111. AndroidComponentUtil.toggleComponent(context, this.getClass(), false);
  112. context.startService(getStartIntent(context));
  113. }
  114. }
  115. }
  116. private static class MangaUpdate {
  117. private Manga manga;
  118. private PostResult result;
  119. public MangaUpdate(Manga manga, PostResult result) {
  120. this.manga = manga;
  121. this.result = result;
  122. }
  123. public Manga getManga() {
  124. return manga;
  125. }
  126. public PostResult getResult() {
  127. return result;
  128. }
  129. }
  130. }