Bugfixes in download manager and other minor changes

This commit is contained in:
inorichi 2015-11-06 20:22:01 +01:00
parent d3a32da62c
commit 17c60644dd
10 changed files with 205 additions and 92 deletions

View file

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application <application
android:name=".App" android:name=".App"

View file

@ -7,12 +7,10 @@ import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import eu.kanade.mangafeed.data.models.Chapter; import eu.kanade.mangafeed.data.models.Chapter;
@ -33,16 +31,18 @@ import timber.log.Timber;
public class DownloadManager { public class DownloadManager {
private PublishSubject<DownloadChaptersEvent> downloadsSubject;
private Subscription downloadSubscription;
private Subscription threadNumberSubscription;
private Context context; private Context context;
private SourceManager sourceManager; private SourceManager sourceManager;
private PreferencesHelper preferences; private PreferencesHelper preferences;
private Gson gson; private Gson gson;
private PublishSubject<Download> downloadsQueueSubject;
private BehaviorSubject<Integer> threadsNumber;
private Subscription downloadsSubscription;
private Subscription threadNumberSubscription;
private DownloadQueue queue; private DownloadQueue queue;
private transient boolean isQueuePaused;
public static final String PAGE_LIST_FILE = "index.json"; public static final String PAGE_LIST_FILE = "index.json";
@ -54,78 +54,63 @@ public class DownloadManager {
queue = new DownloadQueue(); queue = new DownloadQueue();
initializeDownloadSubscription(); initializeDownloadsSubscription();
} }
public PublishSubject<DownloadChaptersEvent> getDownloadsSubject() { private void initializeDownloadsSubscription() {
return downloadsSubject; if (downloadsSubscription != null && !downloadsSubscription.isUnsubscribed())
} downloadsSubscription.unsubscribe();
private void initializeDownloadSubscription() {
if (downloadSubscription != null && !downloadSubscription.isUnsubscribed()) {
downloadSubscription.unsubscribe();
}
if (threadNumberSubscription != null && !threadNumberSubscription.isUnsubscribed()) if (threadNumberSubscription != null && !threadNumberSubscription.isUnsubscribed())
threadNumberSubscription.unsubscribe(); threadNumberSubscription.unsubscribe();
downloadsSubject = PublishSubject.create(); downloadsQueueSubject = PublishSubject.create();
BehaviorSubject<Integer> threads = BehaviorSubject.create(); threadsNumber = BehaviorSubject.create();
threadNumberSubscription = preferences.getDownloadTheadsObs() threadNumberSubscription = preferences.getDownloadTheadsObservable()
.subscribe(threads::onNext); .filter(n -> !isQueuePaused)
.doOnNext(n -> isQueuePaused = (n == 0))
.subscribe(threadsNumber::onNext);
// Listen for download events, add them to queue and download downloadsSubscription = downloadsQueueSubject
downloadSubscription = downloadsSubject .observeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io()) .lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber))
.flatMap(this::prepareDownloads)
.lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threads))
.onBackpressureBuffer() .onBackpressureBuffer()
.subscribe(page -> {}, .subscribe(page -> {},
e -> Timber.e(e.fillInStackTrace(), e.getMessage())); e -> Timber.e(e.fillInStackTrace(), e.getMessage()));
} }
// Create a download object for every chapter and add it to the downloads queue // Create a download object for every chapter in the event and add them to the downloads queue
private Observable<Download> prepareDownloads(DownloadChaptersEvent event) { public void onDownloadChaptersEvent(DownloadChaptersEvent event) {
final Manga manga = event.getManga(); final Manga manga = event.getManga();
final Source source = sourceManager.get(manga.source); final Source source = sourceManager.get(manga.source);
List<Download> downloads = new ArrayList<>();
for (Chapter chapter : event.getChapters()) { for (Chapter chapter : event.getChapters()) {
Download download = new Download(source, manga, chapter); Download download = new Download(source, manga, chapter);
if (!isChapterDownloaded(download)) { if (!isChapterDownloaded(download)) {
queue.add(download); queue.add(download);
downloads.add(download); downloadsQueueSubject.onNext(download);
} }
} }
return Observable.from(downloads);
} }
// Check if a chapter is already downloaded // Check if a chapter is already downloaded
private boolean isChapterDownloaded(Download download) { private boolean isChapterDownloaded(Download download) {
// If the chapter is already queued, don't add it again // If the chapter is already queued, don't add it again
for (Download queuedDownload : queue.get()) { for (Download queuedDownload : queue.get()) {
if (download.chapter.id == queuedDownload.chapter.id) if (download.chapter.id.equals(queuedDownload.chapter.id))
return true; return true;
} }
// Add the directory to the download object for future access // Add the directory to the download object for future access
download.directory = getAbsoluteChapterDirectory(download); download.directory = getAbsoluteChapterDirectory(download);
// If the directory doesn't exist, the chapter isn't downloaded. Create it in this case // If the directory doesn't exist, the chapter isn't downloaded.
if (!download.directory.exists()) { if (!download.directory.exists()) {
// FIXME Sometimes it's failing to create the directory... My fault?
try {
DiskUtils.createDirectory(download.directory);
} catch (IOException e) {
Timber.e("Unable to create directory for chapter");
}
return false; return false;
} }
// If the page list doesn't exist, the chapter isn't download (or maybe it's, // If the page list doesn't exist, the chapter isn't download (or maybe it's,
// but we consider it's not) // but we consider it's not)
List<Page> savedPages = getSavedPageList(download); List<Page> savedPages = getSavedPageList(download);
@ -142,6 +127,12 @@ public class DownloadManager {
// Download the entire chapter // Download the entire chapter
private Observable<Page> downloadChapter(Download download) { private Observable<Page> downloadChapter(Download download) {
try {
DiskUtils.createDirectory(download.directory);
} catch (IOException e) {
Timber.e(e.getMessage());
}
Observable<List<Page>> pageListObservable = download.pages == null ? Observable<List<Page>> pageListObservable = download.pages == null ?
// Pull page list from network and add them to download object // Pull page list from network and add them to download object
download.source download.source
@ -152,7 +143,6 @@ public class DownloadManager {
Observable.just(download.pages); Observable.just(download.pages);
return pageListObservable return pageListObservable
.subscribeOn(Schedulers.io())
.doOnNext(pages -> download.setStatus(Download.DOWNLOADING)) .doOnNext(pages -> download.setStatus(Download.DOWNLOADING))
// Get all the URLs to the source images, fetch pages if necessary // Get all the URLs to the source images, fetch pages if necessary
.flatMap(pageList -> Observable.merge( .flatMap(pageList -> Observable.merge(
@ -161,31 +151,29 @@ 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(() -> onChapterDownloaded(download)); .doOnCompleted(() -> onDownloadCompleted(download));
} }
// Get downloaded image if exists, otherwise download it with the method below // Get downloaded image if exists, otherwise download it with the method below
public Observable<Page> getDownloadedImage(final Page page, Source source, File chapterDir) { public Observable<Page> getDownloadedImage(final Page page, Source source, File chapterDir) {
Observable<Page> obs = Observable.just(page); Observable<Page> pageObservable = Observable.just(page);
if (page.getImageUrl() == null) if (page.getImageUrl() == null)
return obs; return pageObservable;
String imageFilename = getImageFilename(page); String imageFilename = getImageFilename(page);
File imagePath = new File(chapterDir, imageFilename); File imagePath = new File(chapterDir, imageFilename);
if (!isImageDownloaded(imagePath)) { if (!isImageDownloaded(imagePath)) {
page.setStatus(Page.DOWNLOAD_IMAGE); page.setStatus(Page.DOWNLOAD_IMAGE);
obs = downloadImage(page, source, chapterDir, imageFilename); pageObservable = downloadImage(page, source, chapterDir, imageFilename);
} }
return obs.flatMap(p -> { return pageObservable
page.setImagePath(imagePath.getAbsolutePath()); .doOnNext(p -> p.setImagePath(imagePath.getAbsolutePath()))
page.setStatus(Page.READY); .doOnNext(p -> p.setStatus(Page.READY))
return Observable.just(page); .doOnError(e -> page.setStatus(Page.ERROR))
}).onErrorResumeNext(e -> { // Allow to download the remaining images
page.setStatus(Page.ERROR); .onErrorResumeNext(e -> Observable.just(page));
return Observable.just(page);
});
} }
// Download the image // Download the image
@ -210,31 +198,46 @@ public class DownloadManager {
} }
private boolean isImageDownloaded(File imagePath) { private boolean isImageDownloaded(File imagePath) {
return imagePath.exists() && !imagePath.isDirectory(); return imagePath.exists();
} }
private void onChapterDownloaded(final Download download) { // Called when a download finishes. This doesn't mean the download was successful, so we check it
download.setStatus(Download.DOWNLOADED); private void onDownloadCompleted(final Download download) {
download.totalProgress = download.pages.size() * 100; checkDownloadIsSuccessful(download);
savePageList(download.source, download.manga, download.chapter, download.pages); savePageList(download);
}
private void checkDownloadIsSuccessful(final Download download) {
int expectedProgress = download.pages.size() * 100;
int actualProgress = 0;
int status = Download.DOWNLOADED;
// If any page has an error, the download result will be error
for (Page page : download.pages) {
actualProgress += page.getProgress();
if (page.getStatus() == Page.ERROR) status = Download.ERROR;
}
// If the download is successful, it's safer to use the expected progress
download.totalProgress = (status == Download.DOWNLOADED) ? expectedProgress : actualProgress;
download.setStatus(status);
} }
// Return the page list from the chapter's directory if it exists, null otherwise // Return the page list from the chapter's directory if it exists, null otherwise
public List<Page> getSavedPageList(Source source, Manga manga, Chapter chapter) { public List<Page> getSavedPageList(Source source, Manga manga, Chapter chapter) {
List<Page> pages = null;
File chapterDir = getAbsoluteChapterDirectory(source, manga, chapter); File chapterDir = getAbsoluteChapterDirectory(source, manga, chapter);
File pagesFile = new File(chapterDir, PAGE_LIST_FILE); File pagesFile = new File(chapterDir, PAGE_LIST_FILE);
try { try {
if (pagesFile.exists()) { if (pagesFile.exists()) {
JsonReader reader = new JsonReader(new FileReader(pagesFile.getAbsolutePath())); JsonReader reader = new JsonReader(new FileReader(pagesFile.getAbsolutePath()));
Type collectionType = new TypeToken<List<Page>>() {}.getType(); Type collectionType = new TypeToken<List<Page>>() {}.getType();
return gson.fromJson(reader, collectionType); pages = gson.fromJson(reader, collectionType);
reader.close();
} }
} catch (FileNotFoundException e) { } catch (Exception e) {
Timber.e(e.fillInStackTrace(), e.getMessage()); Timber.e(e.fillInStackTrace(), e.getMessage());
} }
return null; return pages;
} }
// Shortcut for the method above // Shortcut for the method above
@ -287,4 +290,13 @@ public class DownloadManager {
public DownloadQueue getQueue() { public DownloadQueue getQueue() {
return queue; return queue;
} }
public void pauseDownloads() {
threadsNumber.onNext(0);
}
public void resumeDownloads() {
isQueuePaused = false;
threadsNumber.onNext(preferences.getDownloadThreads());
}
} }

View file

@ -68,7 +68,7 @@ public class PreferencesHelper {
return Integer.parseInt(prefs.getString(getKey(R.string.pref_download_threads_key), "1")); return Integer.parseInt(prefs.getString(getKey(R.string.pref_download_threads_key), "1"));
} }
public Observable<Integer> getDownloadTheadsObs() { public Observable<Integer> getDownloadTheadsObservable() {
return rxPrefs.getString(getKey(R.string.pref_download_threads_key), "1") return rxPrefs.getString(getKey(R.string.pref_download_threads_key), "1")
.asObservable().map(Integer::parseInt); .asObservable().map(Integer::parseInt);
} }

View file

@ -3,6 +3,8 @@ package eu.kanade.mangafeed.data.services;
import android.app.Service; import android.app.Service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.IBinder; import android.os.IBinder;
import javax.inject.Inject; import javax.inject.Inject;
@ -12,14 +14,18 @@ import eu.kanade.mangafeed.App;
import eu.kanade.mangafeed.data.helpers.DownloadManager; import eu.kanade.mangafeed.data.helpers.DownloadManager;
import eu.kanade.mangafeed.events.DownloadChaptersEvent; import eu.kanade.mangafeed.events.DownloadChaptersEvent;
import eu.kanade.mangafeed.util.AndroidComponentUtil; import eu.kanade.mangafeed.util.AndroidComponentUtil;
import eu.kanade.mangafeed.util.ContentObservable;
import eu.kanade.mangafeed.util.EventBusHook; import eu.kanade.mangafeed.util.EventBusHook;
import rx.Subscription;
public class DownloadService extends Service { public class DownloadService extends Service {
@Inject DownloadManager downloadManager; @Inject DownloadManager downloadManager;
public static Intent getStartIntent(Context context) { private Subscription networkChangeSubscription;
return new Intent(context, DownloadService.class);
public static void start(Context context) {
context.startService(new Intent(context, DownloadService.class));
} }
public static boolean isRunning(Context context) { public static boolean isRunning(Context context) {
@ -30,6 +36,7 @@ public class DownloadService extends Service {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
App.get(this).getComponent().inject(this); App.get(this).getComponent().inject(this);
listenNetworkChanges();
EventBus.getDefault().registerSticky(this); EventBus.getDefault().registerSticky(this);
} }
@ -39,6 +46,13 @@ public class DownloadService extends Service {
return START_STICKY; return START_STICKY;
} }
@Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
networkChangeSubscription.unsubscribe();
super.onDestroy();
}
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return null; return null;
@ -46,14 +60,16 @@ public class DownloadService extends Service {
@EventBusHook @EventBusHook
public void onEvent(DownloadChaptersEvent event) { public void onEvent(DownloadChaptersEvent event) {
downloadManager.getDownloadsSubject().onNext(event);
EventBus.getDefault().removeStickyEvent(event); EventBus.getDefault().removeStickyEvent(event);
downloadManager.onDownloadChaptersEvent(event);
} }
@Override private void listenNetworkChanges() {
public void onDestroy() { IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
EventBus.getDefault().unregister(this); networkChangeSubscription = ContentObservable.fromBroadcast(this, intentFilter)
super.onDestroy(); .subscribe(state -> {
// TODO
});
} }
} }

View file

@ -21,7 +21,6 @@ import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.models.Manga; import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.data.services.LibraryUpdateService; import eu.kanade.mangafeed.data.services.LibraryUpdateService;
import eu.kanade.mangafeed.presenter.LibraryPresenter; import eu.kanade.mangafeed.presenter.LibraryPresenter;
import eu.kanade.mangafeed.ui.activity.MainActivity;
import eu.kanade.mangafeed.ui.activity.MangaDetailActivity; import eu.kanade.mangafeed.ui.activity.MangaDetailActivity;
import eu.kanade.mangafeed.ui.adapter.LibraryAdapter; import eu.kanade.mangafeed.ui.adapter.LibraryAdapter;
import eu.kanade.mangafeed.ui.fragment.base.BaseRxFragment; import eu.kanade.mangafeed.ui.fragment.base.BaseRxFragment;
@ -31,7 +30,6 @@ import nucleus.factory.RequiresPresenter;
public class LibraryFragment extends BaseRxFragment<LibraryPresenter> { public class LibraryFragment extends BaseRxFragment<LibraryPresenter> {
@Bind(R.id.gridView) GridView grid; @Bind(R.id.gridView) GridView grid;
private MainActivity activity;
private LibraryAdapter adapter; private LibraryAdapter adapter;
public static LibraryFragment newInstance() { public static LibraryFragment newInstance() {
@ -45,8 +43,6 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter> {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setHasOptionsMenu(true); setHasOptionsMenu(true);
activity = (MainActivity)getActivity();
} }
@Override @Override
@ -54,7 +50,7 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter> {
Bundle savedInstanceState) { Bundle savedInstanceState) {
// Inflate the layout for this fragment // Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_library, container, false); View view = inflater.inflate(R.layout.fragment_library, container, false);
activity.setToolbarTitle(getString(R.string.library_title)); setToolbarTitle(getString(R.string.library_title));
ButterKnife.bind(this, view); ButterKnife.bind(this, view);
createAdapter(); createAdapter();
@ -73,9 +69,9 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter> {
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_refresh: case R.id.action_refresh:
if (!LibraryUpdateService.isRunning(activity)) { if (!LibraryUpdateService.isRunning(getActivity())) {
Intent intent = LibraryUpdateService.getStartIntent(activity); Intent intent = LibraryUpdateService.getStartIntent(getActivity());
activity.startService(intent); getActivity().startService(intent);
} }
return true; return true;

View file

@ -131,8 +131,7 @@ public class MangaChaptersFragment extends BaseRxFragment<MangaChaptersPresenter
getPresenter().markChaptersRead(getSelectedChapters(), false); getPresenter().markChaptersRead(getSelectedChapters(), false);
return true; return true;
case R.id.action_download: case R.id.action_download:
Intent intent = DownloadService.getStartIntent(getActivity()); DownloadService.start(getActivity());
getActivity().startService(intent);
getPresenter().downloadChapters(getSelectedChapters()); getPresenter().downloadChapters(getSelectedChapters());
closeActionMode(); closeActionMode();
return true; return true;

View file

@ -26,19 +26,12 @@ public class SourceFragment extends BaseRxFragment<SourcePresenter> {
@Bind(R.id.catalogue_list) ListView source_list; @Bind(R.id.catalogue_list) ListView source_list;
private MainActivity activity;
private EasyAdapter<Source> adapter; private EasyAdapter<Source> adapter;
public static SourceFragment newInstance() { public static SourceFragment newInstance() {
return new SourceFragment(); return new SourceFragment();
} }
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = (MainActivity)getActivity();
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
@ -56,6 +49,7 @@ public class SourceFragment extends BaseRxFragment<SourcePresenter> {
@OnItemClick(R.id.catalogue_list) @OnItemClick(R.id.catalogue_list)
public void onSourceClick(int position) { public void onSourceClick(int position) {
Source source = adapter.getItem(position); Source source = adapter.getItem(position);
MainActivity activity = (MainActivity) getActivity();
if (getPresenter().isValidSource(source)) { if (getPresenter().isValidSource(source)) {
CatalogueFragment fragment = CatalogueFragment.newInstance(source.getSourceId()); CatalogueFragment fragment = CatalogueFragment.newInstance(source.getSourceId());
@ -66,7 +60,7 @@ public class SourceFragment extends BaseRxFragment<SourcePresenter> {
} }
private void createAdapter() { private void createAdapter() {
adapter = new EasyAdapter<>(activity, SourceHolder.class); adapter = new EasyAdapter<>(getActivity(), SourceHolder.class);
source_list.setAdapter(adapter); source_list.setAdapter(adapter);
} }

View file

@ -7,11 +7,15 @@ import eu.kanade.mangafeed.ui.activity.base.BaseActivity;
public class BaseFragment extends Fragment { public class BaseFragment extends Fragment {
public void setToolbarTitle(String title) { public void setToolbarTitle(String title) {
((BaseActivity)getActivity()).setToolbarTitle(title); getBaseActivity().setToolbarTitle(title);
} }
public void setToolbarTitle(int resourceId) { public void setToolbarTitle(int resourceId) {
((BaseActivity)getActivity()).setToolbarTitle(getString(resourceId)); getBaseActivity().setToolbarTitle(getString(resourceId));
}
public BaseActivity getBaseActivity() {
return (BaseActivity) getActivity();
} }
} }

View file

@ -0,0 +1,93 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package eu.kanade.mangafeed.util;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
public final class ContentObservable {
private ContentObservable() {
throw new AssertionError("No instances");
}
/**
* Create Observable that wraps BroadcastReceiver and emits received intents.
*
* @param filter Selects the Intent broadcasts to be received.
*/
public static Observable<Intent> fromBroadcast(Context context, IntentFilter filter){
return Observable.create(new OnSubscribeBroadcastRegister(context, filter, null, null));
}
/**
* Create Observable that wraps BroadcastReceiver and emits received intents.
*
* @param filter Selects the Intent broadcasts to be received.
* @param broadcastPermission String naming a permissions that a
* broadcaster must hold in order to send an Intent to you. If null,
* no permission is required.
* @param schedulerHandler Handler identifying the thread that will receive
* the Intent. If null, the main thread of the process will be used.
*/
public static Observable<Intent> fromBroadcast(Context context, IntentFilter filter, String broadcastPermission, Handler schedulerHandler){
return Observable.create(new OnSubscribeBroadcastRegister(context, filter, broadcastPermission, schedulerHandler));
}
static class OnSubscribeBroadcastRegister implements Observable.OnSubscribe<Intent> {
private final Context context;
private final IntentFilter intentFilter;
private final String broadcastPermission;
private final Handler schedulerHandler;
public OnSubscribeBroadcastRegister(Context context, IntentFilter intentFilter, String broadcastPermission, Handler schedulerHandler) {
this.context = context;
this.intentFilter = intentFilter;
this.broadcastPermission = broadcastPermission;
this.schedulerHandler = schedulerHandler;
}
@Override
public void call(final Subscriber<? super Intent> subscriber) {
final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
subscriber.onNext(intent);
}
};
final Subscription subscription = Subscriptions.create(new Action0() {
@Override
public void call() {
context.unregisterReceiver(broadcastReceiver);
}
});
subscriber.add(subscription);
context.registerReceiver(broadcastReceiver, intentFilter, broadcastPermission, schedulerHandler);
}
}
}

View file

@ -115,9 +115,7 @@ public final class DiskUtils {
} }
public static File saveBufferedSourceToDirectory(BufferedSource bufferedSource, File directory, String name) throws IOException { public static File saveBufferedSourceToDirectory(BufferedSource bufferedSource, File directory, String name) throws IOException {
if (!directory.exists() && !directory.mkdirs()) { createDirectory(directory);
throw new IOException("Failed Creating Directory");
}
File writeFile = new File(directory, name); File writeFile = new File(directory, name);
if (writeFile.exists()) { if (writeFile.exists()) {