Search in sources :

Example 6 with Function

use of com.ichi2.utils.FunctionalInterfaces.Function in project Anki-Android by ankidroid.

the class AudioPlayerTest method testStopWithIOException.

// tests if the stop() function successfully catches an IOException
@Test
public void testStopWithIOException() {
    ShadowMediaPlayer.addException(DataSource.toDataSource(mFile.getAbsolutePath()), new IOException("Expected"));
    assertDoesNotThrow(() -> {
        mAudioPlayer.stop();
    });
}
Also used : IOException(java.io.IOException) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 7 with Function

use of com.ichi2.utils.FunctionalInterfaces.Function in project Anki-Android by Ramblurr.

the class BasicTextFieldController method createCloneButton.

/**
 * @param activity
 * @param layoutTools This creates a button, which will call a dialog, allowing to pick from another note's fields
 *            one, and use it's value in the current one.
 * @param p
 */
private void createCloneButton(LinearLayout layoutTools, LayoutParams p) {
    // Makes sense only for two and more fields
    if (mNote.getNumberOfFields() > 1) {
        // Should be more than one text not empty fields for clone to make
        // sense
        mPossibleClones = new ArrayList<String>();
        int numTextFields = 0;
        for (int i = 0; i < mNote.getNumberOfFields(); ++i) {
            // Sort out non text and empty fields
            IField curField = mNote.getField(i);
            if (curField == null) {
                continue;
            }
            if (curField.getType() != EFieldType.TEXT) {
                continue;
            }
            if (curField.getText() == null) {
                continue;
            }
            if (curField.getText().length() == 0) {
                continue;
            }
            // as well as the same field
            if (curField.getText().contentEquals(mField.getText())) {
                continue;
            }
            // collect clone sources
            mPossibleClones.add(curField.getText());
            ++numTextFields;
        }
        // Nothing to clone from
        if (numTextFields < 1) {
            return;
        }
        Button btnOtherField = new Button(mActivity);
        btnOtherField.setText(gtxt(R.string.multimedia_editor_text_field_editing_clone));
        layoutTools.addView(btnOtherField, p);
        final BasicTextFieldController controller = this;
        btnOtherField.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                PickStringDialogFragment fragment = new PickStringDialogFragment();
                fragment.setChoices(mPossibleClones);
                fragment.setOnclickListener(controller);
                fragment.setTitle(gtxt(R.string.multimedia_editor_text_field_editing_clone_source));
                fragment.show(mActivity.getSupportFragmentManager(), "pick.clone");
            // flow continues in the onClick function
            }
        });
    }
}
Also used : Button(android.widget.Button) PickStringDialogFragment(com.ichi2.anki.multimediacard.activity.PickStringDialogFragment) OnClickListener(android.view.View.OnClickListener) View(android.view.View)

Example 8 with Function

use of com.ichi2.utils.FunctionalInterfaces.Function 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)

Example 9 with Function

use of com.ichi2.utils.FunctionalInterfaces.Function in project Anki-Android by ankidroid.

the class SchedV2 method _updateCutoff.

/**
 * Daily cutoff ************************************************************* **********************************
 * This function uses GregorianCalendar so as to be sensitive to leap years, daylight savings, etc.
 */
/* Overriden: other way to count time*/
@RustCleanup("remove timing == null check once JavaBackend is removed")
public void _updateCutoff() {
    int oldToday = mToday == null ? 0 : mToday;
    SchedTimingToday timing = _timingToday();
    if (timing == null) {
        mToday = _daysSinceCreation();
        mDayCutoff = _dayCutoff();
    } else if (_new_timezone_enabled()) {
        mToday = timing.days_elapsed();
        mDayCutoff = timing.next_day_at();
    } else {
        mToday = _daysSinceCreation();
        mDayCutoff = _dayCutoff();
    }
    if (oldToday != mToday) {
        mCol.log(mToday, mDayCutoff);
    }
    // instead
    for (Deck deck : mCol.getDecks().all()) {
        update(deck);
    }
    // unbury if the day has rolled over
    int unburied = mCol.get_config("lastUnburied", 0);
    if (unburied < mToday) {
        SyncStatus.ignoreDatabaseModification(this::unburyCards);
        mCol.set_config("lastUnburied", mToday);
    }
}
Also used : SchedTimingToday(com.ichi2.libanki.backend.model.SchedTimingToday) Deck(com.ichi2.libanki.Deck) RustCleanup(net.ankiweb.rsdroid.RustCleanup)

Example 10 with Function

use of com.ichi2.utils.FunctionalInterfaces.Function in project Anki-Android by ankidroid.

the class Collection method fixIntegrity.

/**
 * Fix possible problems and rebuild caches.
 */
public CheckDatabaseResult fixIntegrity(TaskManager.ProgressCallback<String> 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 = () -> fixIntegrityProgress(progressCallback, currentTask[0]++, totalTasks);
    Consumer<FunctionalInterfaces.FunctionThrowable<Runnable, List<String>, JSONException>> executeIntegrityTask = function -> {
        // DEFECT: notifyProgress will lag if an exception is thrown.
        try {
            mDb.getDatabase().beginTransaction();
            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.w(ex, "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.accept(this::deleteNotesWithMissingModel);
    // for each model
    for (Model m : getModels().all()) {
        executeIntegrityTask.accept((callback) -> deleteCardsWithInvalidModelOrdinals(callback, m));
        executeIntegrityTask.accept((callback) -> deleteNotesWithWrongFieldCounts(callback, m));
    }
    executeIntegrityTask.accept(this::deleteNotesWithMissingCards);
    executeIntegrityTask.accept(this::deleteCardsWithMissingNotes);
    executeIntegrityTask.accept(this::removeOriginalDuePropertyWhereInvalid);
    executeIntegrityTask.accept(this::removeDynamicPropertyFromNonDynamicDecks);
    executeIntegrityTask.accept(this::removeDeckOptionsFromDynamicDecks);
    executeIntegrityTask.accept(this::resetInvalidDeckOptions);
    executeIntegrityTask.accept(this::rebuildTags);
    executeIntegrityTask.accept(this::updateFieldCache);
    executeIntegrityTask.accept(this::fixNewCardDuePositionOverflow);
    executeIntegrityTask.accept(this::resetNewCardInsertionPosition);
    executeIntegrityTask.accept(this::fixExcessiveReviewDueDates);
    // v2 sched had a bug that could create decimal intervals
    executeIntegrityTask.accept(this::fixDecimalCardsData);
    executeIntegrityTask.accept(this::fixDecimalRevLogData);
    executeIntegrityTask.accept(this::restoreMissingDatabaseIndices);
    executeIntegrityTask.accept(this::ensureModelsAreNotEmpty);
    executeIntegrityTask.accept((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 : TemplateRenderOutput(com.ichi2.libanki.TemplateManager.TemplateRenderContext.TemplateRenderOutput) Arrays(java.util.Arrays) TaskManager(com.ichi2.async.TaskManager) NonNull(androidx.annotation.NonNull) UsageAnalytics(com.ichi2.anki.analytics.UsageAnalytics) AbstractSched(com.ichi2.libanki.sched.AbstractSched) Random(java.util.Random) DroidBackend(com.ichi2.libanki.backend.DroidBackend) Time(com.ichi2.libanki.utils.Time) FunctionalInterfaces(com.ichi2.utils.FunctionalInterfaces) ParsedNode(com.ichi2.libanki.template.ParsedNode) KotlinCleanup(com.ichi2.utils.KotlinCleanup) SupportSQLiteDatabase(androidx.sqlite.db.SupportSQLiteDatabase) Locale(java.util.Locale) UIUtils(com.ichi2.anki.UIUtils) Map(java.util.Map) CancelListener.isCancelled(com.ichi2.async.CancelListener.isCancelled) JSONException(com.ichi2.utils.JSONException) SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) PrintWriter(java.io.PrintWriter) Upgrade(com.ichi2.upgrade.Upgrade) HashUtil(com.ichi2.utils.HashUtil) GregorianCalendar(java.util.GregorianCalendar) Set(java.util.Set) JSONObject(com.ichi2.utils.JSONObject) Timber(timber.log.Timber) CancelListener(com.ichi2.async.CancelListener) Contract(org.jetbrains.annotations.Contract) List(java.util.List) BackendNotSupportedException(com.ichi2.libanki.backend.exception.BackendNotSupportedException) Nullable(androidx.annotation.Nullable) AnkiDroidApp(com.ichi2.anki.AnkiDroidApp) ContentValues(android.content.ContentValues) UnknownDatabaseVersionException(com.ichi2.libanki.exception.UnknownDatabaseVersionException) Pattern(java.util.regex.Pattern) VersionUtils(com.ichi2.utils.VersionUtils) RustCleanup(net.ankiweb.rsdroid.RustCleanup) Context(android.content.Context) Pair(android.util.Pair) R(com.ichi2.anki.R) HashMap(java.util.HashMap) Sched(com.ichi2.libanki.sched.Sched) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) SuppressLint(android.annotation.SuppressLint) JSONArray(com.ichi2.utils.JSONArray) Calendar(java.util.Calendar) ProgressSender(com.ichi2.async.ProgressSender) ChessFilter(com.ichi2.libanki.hooks.ChessFilter) SupportSQLiteStatement(androidx.sqlite.db.SupportSQLiteStatement) Cursor(android.database.Cursor) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) CheckResult(androidx.annotation.CheckResult) BufferedWriter(java.io.BufferedWriter) FileWriter(java.io.FileWriter) SchedV2(com.ichi2.libanki.sched.SchedV2) TextUtils(android.text.TextUtils) CollectionTask(com.ichi2.async.CollectionTask) TemplateError(com.ichi2.libanki.template.TemplateError) IOException(java.io.IOException) File(java.io.File) Consumer(java.util.function.Consumer) NoSuchDeckException(com.ichi2.libanki.exception.NoSuchDeckException) LinkedBlockingDeque(java.util.concurrent.LinkedBlockingDeque) Collections(java.util.Collections) VisibleForTesting(androidx.annotation.VisibleForTesting) Resources(android.content.res.Resources) SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) SuppressLint(android.annotation.SuppressLint) JSONException(com.ichi2.utils.JSONException) SQLiteDatabaseLockedException(android.database.sqlite.SQLiteDatabaseLockedException) BackendNotSupportedException(com.ichi2.libanki.backend.exception.BackendNotSupportedException) UnknownDatabaseVersionException(com.ichi2.libanki.exception.UnknownDatabaseVersionException) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) IOException(java.io.IOException) NoSuchDeckException(com.ichi2.libanki.exception.NoSuchDeckException) File(java.io.File)

Aggregations

Deck (com.ichi2.libanki.Deck)4 IOException (java.io.IOException)4 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)3 JSONException (com.ichi2.utils.JSONException)3 File (java.io.File)3 ArrayList (java.util.ArrayList)3 List (java.util.List)3 SuppressLint (android.annotation.SuppressLint)2 SQLiteDatabaseLockedException (android.database.sqlite.SQLiteDatabaseLockedException)2 Button (android.widget.Button)2 PickStringDialogFragment (com.ichi2.anki.multimediacard.activity.PickStringDialogFragment)2 NoSuchDeckException (com.ichi2.libanki.exception.NoSuchDeckException)2 FunctionalInterfaces (com.ichi2.utils.FunctionalInterfaces)2 JSONObject (com.ichi2.utils.JSONObject)2 RustCleanup (net.ankiweb.rsdroid.RustCleanup)2 ContentResolver (android.content.ContentResolver)1 ContentValues (android.content.ContentValues)1 Context (android.content.Context)1 Resources (android.content.res.Resources)1 Cursor (android.database.Cursor)1