0
0
mirror of https://github.com/ankidroid/Anki-Android.git synced 2024-09-20 20:03:05 +02:00

colIsOpen check in DeckPicker before dependent ops

- Since colIsOpen() is always true if its possible to open Collection..
- Maintains same behavior, but uses colIsOpen instead of getColSafe in:
    - onPrepareOptionsMenu()
    - onResume()
- Call displaySyncBadge from onCreateOptionsMenu() only if colIsOpen()
- No more predictable StorageAccessExceptions from getColSafe()
This commit is contained in:
Farjad Ilyas 2021-04-23 11:14:14 +05:00 committed by Mike Hardy
parent e70b586b61
commit b8093d9c7a
2 changed files with 97 additions and 10 deletions

View File

@ -666,7 +666,7 @@ public class DeckPicker extends NavigationDrawerActivity implements
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Null check to prevent crash when col inaccessible
if (CollectionHelper.getInstance().getColSafe(this) == null) {
if (!colIsOpen()) {
return false;
}
return super.onPrepareOptionsMenu(menu);
@ -683,13 +683,6 @@ public class DeckPicker extends NavigationDrawerActivity implements
menu.findItem(R.id.action_check_media).setEnabled(sdCardAvailable);
menu.findItem(R.id.action_empty_cards).setEnabled(sdCardAvailable);
// I haven't had an exception here, but it feels this may be flaky
try {
displaySyncBadge(menu);
} catch (Exception e) {
Timber.w(e, "Error Displaying Sync Badge");
}
MenuItem toolbarSearchItem = menu.findItem(R.id.deck_picker_action_filter);
mToolbarSearchView = (SearchView) toolbarSearchItem.getActionView();
@ -710,6 +703,8 @@ public class DeckPicker extends NavigationDrawerActivity implements
});
if (colIsOpen()) {
displaySyncBadge(menu);
// Show / hide undo
if (mFragmented || !getCol().undoAvailable()) {
menu.findItem(R.id.action_undo).setVisible(false);
@ -729,7 +724,8 @@ public class DeckPicker extends NavigationDrawerActivity implements
}
private void displaySyncBadge(Menu menu) {
@VisibleForTesting
protected void displaySyncBadge(Menu menu) {
MenuItem syncMenu = menu.findItem(R.id.action_sync);
SyncStatus syncStatus = SyncStatus.getSyncStatus(this::getCol);
switch (syncStatus) {
@ -944,7 +940,9 @@ public class DeckPicker extends NavigationDrawerActivity implements
}
/* Complete task and enqueue fetching nonessential data for
startup. */
TaskManager.launchCollectionTask(new CollectionTask.LoadCollectionComplete());
if (colIsOpen()) {
TaskManager.launchCollectionTask(new CollectionTask.LoadCollectionComplete());
}
// Update sync status (if we've come back from a screen)
supportInvalidateOptionsMenu();
}

View File

@ -5,6 +5,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.view.Menu;
import com.ichi2.anki.dialogs.DatabaseErrorDialog;
import com.ichi2.libanki.Collection;
@ -26,6 +27,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import static com.ichi2.anki.DeckPicker.UPGRADE_VERSION_KEY;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
@ -266,9 +269,82 @@ public class DeckPickerTest extends RobolectricTest {
}
}
@Test
public void doNotShowOptionsMenuWhenCollectionInaccessible() {
try {
enableNullCollection();
DeckPickerEx d = super.startActivityNormallyOpenCollectionWithIntent(DeckPickerEx.class, new Intent());
assertThat("Options menu not displayed when collection is inaccessible", d.mPrepareOptionsMenu, is(false));
} finally {
disableNullCollection();
}
}
@Test
public void showOptionsMenuWhenCollectionAccessible() {
try {
InitialActivityTest.grantWritePermissions();
DeckPickerEx d = super.startActivityNormallyOpenCollectionWithIntent(DeckPickerEx.class, new Intent());
assertThat("Options menu is displayed when collection is accessible", d.mPrepareOptionsMenu, is(true));
} finally {
InitialActivityTest.revokeWritePermissions();
}
}
@Test
public void doNotShowSyncBadgeWhenCollectionInaccessible() {
try {
enableNullCollection();
DeckPickerEx d = super.startActivityNormallyOpenCollectionWithIntent(DeckPickerEx.class, new Intent());
assertThat("Sync badge is not displayed when collection is inaccessible", d.mDisplaySyncBadge, is(false));
} finally {
disableNullCollection();
}
}
@Test
public void showSyncBadgeWhenCollectionAccessible() {
try {
InitialActivityTest.grantWritePermissions();
DeckPickerEx d = super.startActivityNormallyOpenCollectionWithIntent(DeckPickerEx.class, new Intent());
assertThat("Sync badge is displayed when collection is accessible", d.mDisplaySyncBadge, is(true));
} finally {
InitialActivityTest.revokeWritePermissions();
}
}
@Test
public void onResumeLoadCollectionFailureWithInaccessibleCollection() {
try {
InitialActivityTest.revokeWritePermissions();
enableNullCollection();
DeckPickerEx d = super.startActivityNormallyOpenCollectionWithIntent(DeckPickerEx.class, new Intent());
// Neither collection, not its models will be initialized without storage permission
assertThat("Lazy Collection initialization CollectionTask.LoadCollectionComplete fails", d.getCol(), is(nullValue()));
} finally {
disableNullCollection();
}
}
@Test
public void onResumeLoadCollectionSuccessWithAccessibleCollection() {
try {
InitialActivityTest.grantWritePermissions();
DeckPickerEx d = super.startActivityNormallyOpenCollectionWithIntent(DeckPickerEx.class, new Intent());
assertThat("Collection initialization ensured by CollectionTask.LoadCollectionComplete", d.getCol(), is(notNullValue()));
assertThat("Collection Models Loaded", d.getCol().getModels(), is(notNullValue()));
} finally {
InitialActivityTest.revokeWritePermissions();
}
}
private static class DeckPickerEx extends DeckPicker {
private int mDatabaseErrorDialog;
private boolean mDisplayedAnalyticsOptIn;
private boolean mPrepareOptionsMenu;
private boolean mDisplaySyncBadge = false;
@Override
@ -286,5 +362,18 @@ public class DeckPickerTest extends RobolectricTest {
this.mDisplayedAnalyticsOptIn = true;
super.displayAnalyticsOptInDialog();
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
this.mPrepareOptionsMenu = super.onPrepareOptionsMenu(menu);
return mPrepareOptionsMenu;
}
@Override
protected void displaySyncBadge(Menu menu) {
this.mDisplaySyncBadge = true;
super.displaySyncBadge(menu);
}
}
}