Search in sources :

Example 36 with Sched

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);
}
Also used : AbstractSched(com.ichi2.libanki.sched.AbstractSched) Collection(com.ichi2.libanki.Collection) Card(com.ichi2.libanki.Card)

Example 37 with Sched

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);
}
Also used : Undoable(com.ichi2.libanki.Undoable) AbstractSched(com.ichi2.libanki.sched.AbstractSched) ArrayList(java.util.ArrayList) Card(com.ichi2.libanki.Card) Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) JSONObject(com.ichi2.utils.JSONObject)

Example 38 with Sched

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;
}
Also used : AbstractSched(com.ichi2.libanki.sched.AbstractSched) AbstractSched(com.ichi2.libanki.sched.AbstractSched) Sched(com.ichi2.libanki.sched.Sched) SchedV2(com.ichi2.libanki.sched.SchedV2)

Example 39 with 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);
}
Also used : AbstractSched(com.ichi2.libanki.sched.AbstractSched) Collection(com.ichi2.libanki.Collection) Cursor(android.database.Cursor) Card(com.ichi2.libanki.Card) Test(org.junit.Test)

Example 40 with Sched

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;
}
Also used : SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) JSONException(com.ichi2.utils.JSONException) SuppressLint(android.annotation.SuppressLint) JSONException(com.ichi2.utils.JSONException) SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) IOException(java.io.IOException) NoSuchDeckException(com.ichi2.libanki.exception.NoSuchDeckException) JSONObject(com.ichi2.utils.JSONObject) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) File(java.io.File) FunctionalInterfaces(com.ichi2.utils.FunctionalInterfaces)

Aggregations

Card (com.ichi2.libanki.Card)44 Collection (com.ichi2.libanki.Collection)38 Test (org.junit.Test)35 RobolectricTest (com.ichi2.anki.RobolectricTest)28 Note (com.ichi2.libanki.Note)19 AbstractSched (com.ichi2.libanki.sched.AbstractSched)18 DeckConfig (com.ichi2.libanki.DeckConfig)11 JSONObject (com.ichi2.utils.JSONObject)9 Cursor (android.database.Cursor)7 Sched (com.ichi2.libanki.Sched)6 SchedV2 (com.ichi2.libanki.sched.SchedV2)6 JSONArray (com.ichi2.utils.JSONArray)6 SuppressLint (android.annotation.SuppressLint)4 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)4 DB (com.ichi2.libanki.DB)4 Model (com.ichi2.libanki.Model)4 Sched (com.ichi2.libanki.sched.Sched)4 ArrayList (java.util.ArrayList)4 Matchers.containsString (org.hamcrest.Matchers.containsString)4 ContentValues (android.content.ContentValues)3