From 80238f3cf28a6db8f97691a36f3c48d33aa3ad2b Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Wed, 3 Sep 2014 22:49:18 -0400 Subject: [PATCH] Handle no books installed on start properly. --- .../test/activity/viewer/BibleViewerTest.java | 42 +++++++++++ .../activity/viewer/BibleViewer.java | 56 ++++++++------ .../activity/viewer/BibleViewerModules.java | 27 +++++-- .../viewer/ExpListNavDrawerFragment.java | 74 ++++++++++--------- .../org/bspeice/minimalbible/Modules.java | 4 +- .../org/bspeice/minimalbible/TestModules.java | 15 +++- 6 files changed, 150 insertions(+), 68 deletions(-) create mode 100644 app/src/androidTest/java/org/bspeice/minimalbible/test/activity/viewer/BibleViewerTest.java diff --git a/app/src/androidTest/java/org/bspeice/minimalbible/test/activity/viewer/BibleViewerTest.java b/app/src/androidTest/java/org/bspeice/minimalbible/test/activity/viewer/BibleViewerTest.java new file mode 100644 index 0000000..f7b6383 --- /dev/null +++ b/app/src/androidTest/java/org/bspeice/minimalbible/test/activity/viewer/BibleViewerTest.java @@ -0,0 +1,42 @@ +package org.bspeice.minimalbible.test.activity.viewer; + +import android.test.ActivityInstrumentationTestCase2; + +import org.bspeice.minimalbible.Modules; +import org.bspeice.minimalbible.activity.viewer.BibleViewer; +import org.bspeice.minimalbible.activity.viewer.BookManager; +import org.crosswire.jsword.book.Book; + +import java.util.ArrayList; + +import rx.Observable; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class BibleViewerTest extends ActivityInstrumentationTestCase2 { + + public BibleViewerTest() { + super(BibleViewer.class); + } + + public void setUp() { + // For some reason this test requires us to set the dexcache... + System.setProperty("dexmaker.dexcache", getInstrumentation().getTargetContext() + .getCacheDir().toString()); + } + + /** + * It may happen to be the case that we start and there are no installed books. + * This likely triggers a runtime exception from Rx, and is no excuse for dying. + */ + public void testInitializationNoInstalledBooks() { + BookManager mockBookManager = mock(BookManager.class); + when(mockBookManager.getInstalledBooks()).thenReturn( + Observable.from(new ArrayList())); + Modules.testModules.setBookManager(mockBookManager); + + assertNotNull(getActivity()); + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java index 84948cd..a2bc84a 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java @@ -25,6 +25,7 @@ import javax.inject.Inject; import dagger.ObjectGraph; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; +import rx.functions.Func1; public class BibleViewer extends BaseActivity implements NavDrawerFragment.NavigationDrawerCallbacks, @@ -66,35 +67,42 @@ public class BibleViewer extends BaseActivity implements bvObjectGraph.inject(o); } - @Override + /** + * Set up the application + * TODO: Get the main book, rather than the first installed book. + * + * @param savedInstanceState Android's savedInstanceState + */ + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.inject(this); - // If no books are installed, we need to download one first. - int count = bookManager.getInstalledBooks() - .count() - .toBlocking() - .last(); - if (count <= 0) { - Intent i = new Intent(this, DownloadActivity.class); - startActivityForResult(i, 0); - finish(); - } else { - bookManager.getInstalledBooks() - .first() - .subscribeOn(AndroidSchedulers.mainThread()) - .subscribe(new Action1() { - @Override - public void call(Book book) { - Log.d("BibleViewer", "Subscribed to display book: " + book.getName()); - displayMainBook(book); - } - }); - } - - setContentView(R.layout.activity_bible_viewer); + // If no books are installed, we need to download one first. However, + // RxJava will error if there's nothing installed. + bookManager.getInstalledBooks() + .first() + .onErrorReturn(new Func1() { + @Override + public Book call(Throwable throwable) { + // If there are no books installed... + Log.e(getLocalClassName(), "No books are currently installed, starting DownloadManager"); + Intent i = new Intent(BibleViewer.this, DownloadActivity.class); + startActivityForResult(i, 0); + finish(); + return null; + } + }) + .subscribeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1() { + @Override + public void call(Book book) { + Log.e("BibleViewer", "Subscribed to display book: " + book.getName()); + displayMainBook(book); + } + }); + setContentView(R.layout.activity_bible_viewer); mNavigationDrawerFragment = (ExpListNavDrawerFragment) getSupportFragmentManager() .findFragmentById(R.id.navigation_drawer); diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java index 3070d31..4d3f769 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java @@ -2,13 +2,12 @@ package org.bspeice.minimalbible.activity.viewer; import android.util.Log; -import com.google.gson.Gson; - import org.bspeice.minimalbible.activity.navigation.ExpListNavAdapter; import org.bspeice.minimalbible.activity.viewer.bookutil.VersificationUtil; import org.bspeice.minimalbible.service.book.VerseLookupModules; import org.crosswire.jsword.book.Book; +import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicReference; import javax.inject.Named; @@ -69,13 +68,25 @@ public class BibleViewerModules { }); if (mBook.get() == null) { - Book fallback; - fallback = bookManager.getInstalledBooks() - .toBlocking().first(); - - prefs.defaultBookName(fallback.getName()); - return fallback; + try { + Book fallback; + fallback = bookManager.getInstalledBooks() + .onErrorReturn(new Func1() { + @Override + public Book call(Throwable throwable) { + // If there's no book installed, we can't select the main one... + return null; + } + }) + .toBlocking().first(); + prefs.defaultBookName(fallback.getName()); + return fallback; + } catch (NoSuchElementException e) { + // If no books are installed, there's really nothing we can do... + Log.d("BibleViewerModules", "No books are installed, so can't select a main book."); + return null; + } } else { return mBook.get(); } diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ExpListNavDrawerFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ExpListNavDrawerFragment.java index 474eab9..272e963 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ExpListNavDrawerFragment.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ExpListNavDrawerFragment.java @@ -58,46 +58,52 @@ public class ExpListNavDrawerFragment extends NavDrawerFragment { }); */ - List bibleBooks = vUtil.getBookNames(mainBook) - .toList().toBlocking().first(); + List bibleBooks; + if (mainBook != null) { + bibleBooks = vUtil.getBookNames(mainBook) + .toList().toBlocking().first(); + } else { + bibleBooks = new ArrayList(); + } // I really don't like how we build the chapters, but I'm not adding Guava just for Range. // RXJava does get ridiculous with the angle brackets, you have me there. But Intellij // folds nicely. - Map> chapterMap = - vUtil.getBooks(mainBook).map(new Func1>>() { - @Override - public Map> call(BibleBook bibleBook) { - // These lines are important - int bookCount = vUtil.getChapterCount(mainBook, bibleBook); - List chapterList = new ArrayList(bookCount); - for (int i = 0; i < bookCount; i++) { - chapterList.add(i + 1); // Index to chapter number - } - // - Map> bookListMap = - new HashMap>(1); - bookListMap.put(vUtil.getBookName(mainBook, bibleBook), chapterList); - return bookListMap; + Map> chapterMap = new HashMap>(); + if (mainBook != null) { + vUtil.getBooks(mainBook).map(new Func1>>() { + @Override + public Map> call(BibleBook bibleBook) { + // These lines are important + int bookCount = vUtil.getChapterCount(mainBook, bibleBook); + List chapterList = new ArrayList(bookCount); + for (int i = 0; i < bookCount; i++) { + chapterList.add(i + 1); // Index to chapter number } - }) - .reduce(new Func2>, - Map>, - Map>>() { - @Override - public Map> - call(Map> acc, - Map> value) { - // These lines are important - acc.putAll(value); - return acc; - // - } - }) - .toBlocking() - .first(); - + // + Map> bookListMap = + new HashMap>(1); + bookListMap.put(vUtil.getBookName(mainBook, bibleBook), chapterList); + return bookListMap; + } + }) + .reduce(new Func2>, + Map>, + Map>>() { + @Override + public Map> + call(Map> acc, + Map> value) { + // These lines are important + acc.putAll(value); + return acc; + // + } + }) + .toBlocking() + .first(); + } ExpListNavAdapter adapter = new ExpListNavAdapter(bibleBooks, chapterMap); diff --git a/app/src/testConfig/java/org/bspeice/minimalbible/Modules.java b/app/src/testConfig/java/org/bspeice/minimalbible/Modules.java index 652e2bb..0879293 100644 --- a/app/src/testConfig/java/org/bspeice/minimalbible/Modules.java +++ b/app/src/testConfig/java/org/bspeice/minimalbible/Modules.java @@ -6,12 +6,14 @@ package org.bspeice.minimalbible; */ public class Modules { + public static TestModules testModules = new TestModules(); + private Modules() {} public static Object[] list(MinimalBible app) { return new Object[] { new MinimalBibleModules(app), - new TestModules() + testModules }; } } diff --git a/app/src/testConfig/java/org/bspeice/minimalbible/TestModules.java b/app/src/testConfig/java/org/bspeice/minimalbible/TestModules.java index f6560a2..a0162f7 100644 --- a/app/src/testConfig/java/org/bspeice/minimalbible/TestModules.java +++ b/app/src/testConfig/java/org/bspeice/minimalbible/TestModules.java @@ -2,6 +2,7 @@ package org.bspeice.minimalbible; import org.bspeice.minimalbible.activity.downloader.DownloadActivity; +import org.bspeice.minimalbible.activity.viewer.BookManager; import org.crosswire.jsword.book.BookCategory; import java.util.ArrayList; @@ -22,7 +23,10 @@ import dagger.Provides; public class TestModules { public static CharSequence testActivityTitle = "Test"; - @Provides CharSequence provideString() { + private BookManager bookManager; + + @Provides + CharSequence provideString() { return testActivityTitle; } @@ -36,4 +40,13 @@ public class TestModules { add(BookCategory.MAPS); }}; } + + public void setBookManager(BookManager bookManager) { + this.bookManager = bookManager; + } + + @Provides + BookManager provideBookManager() { + return bookManager; + } }