use of com.ichi2.libanki.sched.Sched in project AnkiChinaAndroid by ankichinateam.
the class CollectionTask method doInBackgroundUndo.
private TaskData doInBackgroundUndo() {
Collection col = getCol();
AbstractSched sched = col.getSched();
try {
col.getDb().getDatabase().beginTransaction();
try {
Card card = nonTaskUndo(col);
publishProgress(new TaskData(card, 0));
col.getDb().getDatabase().setTransactionSuccessful();
} finally {
col.getDb().getDatabase().endTransaction();
}
} catch (RuntimeException e) {
Timber.e(e, "doInBackgroundUndo - RuntimeException on undoing");
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundUndo");
return new TaskData(false);
}
return new TaskData(true);
}
use of com.ichi2.libanki.sched.Sched in project AnkiChinaAndroid by ankichinateam.
the class CollectionTask method doInBackgroundDismissNote.
private TaskData doInBackgroundDismissNote(TaskData param) {
Collection col = getCol();
AbstractSched sched = col.getSched();
Object[] data = param.getObjArray();
Card card = (Card) data[0];
Collection.DismissType type = (Collection.DismissType) data[1];
Note note = card.note();
try {
col.getDb().getDatabase().beginTransaction();
try {
sched.deferReset();
switch(type) {
case BURY_CARD:
// collect undo information
Undoable buryCard = revertToProvidedState(BURY_CARD, card);
col.markUndo(buryCard);
// then bury
sched.buryCards(new long[] { card.getId() });
break;
case BURY_NOTE:
// collect undo information
Undoable buryNote = revertToProvidedState(BURY_NOTE, card);
col.markUndo(buryNote);
// then bury
sched.buryNote(note.getId());
break;
case SUSPEND_CARD:
// collect undo information
Card suspendedCard = card.clone();
Undoable suspendCard = new UndoSuspendCard(suspendedCard);
col.markUndo(suspendCard);
// suspend card
if (card.getQueue() == Consts.QUEUE_TYPE_SUSPENDED) {
sched.unsuspendCards(new long[] { card.getId() });
} else {
sched.suspendCards(new long[] { card.getId() });
}
break;
case SUSPEND_NOTE:
{
// collect undo information
ArrayList<Card> cards = note.cards();
long[] cids = new long[cards.size()];
for (int i = 0; i < cards.size(); i++) {
cids[i] = cards.get(i).getId();
}
col.markUndo(revertToProvidedState(SUSPEND_NOTE, card));
// suspend note
sched.suspendCards(cids);
break;
}
case DELETE_NOTE:
{
// collect undo information
ArrayList<Card> allCs = note.cards();
Undoable deleteNote = new UndoDeleteNote(note, allCs, card);
col.markUndo(deleteNote);
// delete note
col.remNotes(new long[] { note.getId() });
break;
}
}
// With sHadCardQueue set, getCard() resets the scheduler prior to getting the next card
publishProgress(new TaskData(col.getSched().getCard(), 0));
col.getDb().getDatabase().setTransactionSuccessful();
} finally {
col.getDb().getDatabase().endTransaction();
}
} catch (RuntimeException e) {
Timber.e(e, "doInBackgroundDismissNote - RuntimeException on dismissing note, dismiss type %s", type);
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundDismissNote");
return new TaskData(false);
}
return new TaskData(true);
}
use of com.ichi2.libanki.sched.Sched in project AnkiChinaAndroid by ankichinateam.
the class RobolectricTest method upgradeToSchedV2.
protected SchedV2 upgradeToSchedV2() {
getCol().getConf().put("schedVer", 2);
getCol().setMod();
CollectionHelper.getInstance().closeCollection(true, "upgradeToSchedV2");
AbstractSched sched = getCol().getSched();
// Sched inherits from schedv2...
assertThat("sched should be v2", !(sched instanceof Sched));
return (SchedV2) sched;
}
use of com.ichi2.libanki.sched.Sched in project AnkiChinaAndroid by ankichinateam.
the class ContentProviderTest method testQueryNextCard.
/**
* Test that query for the next card in the schedule returns a valid result without any deck selector
*/
@Test
public void testQueryNextCard() {
Collection col = getCol();
AbstractSched sched = col.getSched();
Cursor reviewInfoCursor = InstrumentationRegistry.getInstrumentation().getTargetContext().getContentResolver().query(FlashCardsContract.ReviewInfo.CONTENT_URI, null, null, null, null);
assertNotNull(reviewInfoCursor);
assertEquals("Check that we actually received one card", 1, reviewInfoCursor.getCount());
reviewInfoCursor.moveToFirst();
int cardOrd = reviewInfoCursor.getInt(reviewInfoCursor.getColumnIndex(FlashCardsContract.ReviewInfo.CARD_ORD));
long noteID = reviewInfoCursor.getLong(reviewInfoCursor.getColumnIndex(FlashCardsContract.ReviewInfo.NOTE_ID));
Card nextCard = null;
for (int i = 0; i < 10; i++) {
// minimizing fails, when sched.reset() randomly chooses between multiple cards
col.reset();
nextCard = sched.getCard();
if (nextCard.note().getId() == noteID && nextCard.getOrd() == cardOrd)
break;
}
assertNotNull("Check that there actually is a next scheduled card", nextCard);
assertEquals("Check that received card and actual card have same note id", nextCard.note().getId(), noteID);
assertEquals("Check that received card and actual card have same card ord", nextCard.getOrd(), cardOrd);
}
use of com.ichi2.libanki.sched.Sched in project AnkiChinaAndroid by ankichinateam.
the class Collection method fixIntegrity.
/**
* Fix possible problems and rebuild caches.
*/
public CheckDatabaseResult fixIntegrity(CollectionTask.ProgressCallback progressCallback) {
File file = new File(mPath);
CheckDatabaseResult result = new CheckDatabaseResult(file.length());
final int[] currentTask = { 1 };
// a few fixes are in all-models loops, the rest are one-offs
int totalTasks = (getModels().all().size() * 4) + 27;
Runnable notifyProgress = progressCallback == null ? null : () -> fixIntegrityProgress(progressCallback, currentTask[0]++, totalTasks);
FunctionalInterfaces.Consumer<FunctionalInterfaces.FunctionThrowable<Runnable, List<String>, JSONException>> executeIntegrityTask = (FunctionalInterfaces.FunctionThrowable<Runnable, List<String>, JSONException> function) -> {
// DEFECT: notifyProgress will lag if an exception is thrown.
try {
mDb.getDatabase().beginTransaction();
if (notifyProgress != null)
result.addAll(function.apply(notifyProgress));
mDb.getDatabase().setTransactionSuccessful();
} catch (Exception e) {
Timber.e(e, "Failed to execute integrity check");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity");
} finally {
try {
mDb.getDatabase().endTransaction();
} catch (Exception e) {
Timber.e(e, "Failed to end integrity check transaction");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity - endTransaction");
}
}
};
try {
mDb.getDatabase().beginTransaction();
save();
notifyProgress.run();
if (!mDb.getDatabase().isDatabaseIntegrityOk()) {
return result.markAsFailed();
}
mDb.getDatabase().setTransactionSuccessful();
} catch (SQLiteDatabaseLockedException ex) {
Timber.e("doInBackgroundCheckDatabase - Database locked");
return result.markAsLocked();
} catch (RuntimeException e) {
Timber.e(e, "doInBackgroundCheckDatabase - RuntimeException on marking card");
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundCheckDatabase");
return result.markAsFailed();
} finally {
// if the database was locked, we never got the transaction.
if (mDb.getDatabase().inTransaction()) {
mDb.getDatabase().endTransaction();
}
}
executeIntegrityTask.consume(this::deleteNotesWithMissingModel);
// for each model
for (JSONObject m : getModels().all()) {
executeIntegrityTask.consume((callback) -> deleteCardsWithInvalidModelOrdinals(callback, m));
executeIntegrityTask.consume((callback) -> deleteNotesWithWrongFieldCounts(callback, m));
}
executeIntegrityTask.consume(this::deleteNotesWithMissingCards);
executeIntegrityTask.consume(this::deleteCardsWithMissingNotes);
executeIntegrityTask.consume(this::removeOriginalDuePropertyWhereInvalid);
executeIntegrityTask.consume(this::removeDynamicPropertyFromNonDynamicDecks);
executeIntegrityTask.consume(this::removeDeckOptionsFromDynamicDecks);
executeIntegrityTask.consume(this::resetInvalidDeckOptions);
executeIntegrityTask.consume(this::rebuildTags);
executeIntegrityTask.consume(this::updateFieldCache);
executeIntegrityTask.consume(this::fixNewCardDuePositionOverflow);
executeIntegrityTask.consume(this::resetNewCardInsertionPosition);
executeIntegrityTask.consume(this::fixExcessiveReviewDueDates);
// v2 sched had a bug that could create decimal intervals
executeIntegrityTask.consume(this::fixDecimalCardsData);
executeIntegrityTask.consume(this::fixDecimalRevLogData);
executeIntegrityTask.consume(this::restoreMissingDatabaseIndices);
executeIntegrityTask.consume(this::ensureModelsAreNotEmpty);
executeIntegrityTask.consume((progressNotifier) -> this.ensureCardsHaveHomeDeck(progressNotifier, result));
// and finally, optimize (unable to be done inside transaction).
try {
optimize(notifyProgress);
} catch (Exception e) {
Timber.e(e, "optimize");
AnkiDroidApp.sendExceptionReport(e, "fixIntegrity - optimize");
}
file = new File(mPath);
long newSize = file.length();
result.setNewSize(newSize);
// if any problems were found, force a full sync
if (result.hasProblems()) {
modSchemaNoCheck();
}
logProblems(result.getProblems());
return result;
}
Aggregations