Search in sources :

Example 1 with DB

use of com.ichi2.libanki.DB in project AnkiChinaAndroid by ankichinateam.

the class ContentProviderTest method testInsertAndRemoveNote.

/**
 * Check that inserting and removing a note into default deck works as expected
 */
@Test
public void testInsertAndRemoveNote() {
    // Get required objects for test
    final ContentResolver cr = InstrumentationRegistry.getInstrumentation().getTargetContext().getContentResolver();
    // Add the note
    ContentValues values = new ContentValues();
    values.put(FlashCardsContract.Note.MID, mModelId);
    values.put(FlashCardsContract.Note.FLDS, Utils.joinFields(TEST_NOTE_FIELDS));
    values.put(FlashCardsContract.Note.TAGS, TEST_TAG);
    Uri newNoteUri = cr.insert(FlashCardsContract.Note.CONTENT_URI, values);
    assertNotNull("Check that URI returned from addNewNote is not null", newNoteUri);
    // test that the changes are physically saved to the DB
    final Collection col = reopenCol();
    // Check that it looks as expected
    assertNotNull("check note URI path", newNoteUri.getLastPathSegment());
    Note addedNote = new Note(col, Long.parseLong(newNoteUri.getLastPathSegment()));
    addedNote.load();
    assertArrayEquals("Check that fields were set correctly", addedNote.getFields(), TEST_NOTE_FIELDS);
    assertEquals("Check that tag was set correctly", TEST_TAG, addedNote.getTags().get(0));
    JSONObject model = col.getModels().get(mModelId);
    assertNotNull("Check model", model);
    int expectedNumCards = model.getJSONArray("tmpls").length();
    assertEquals("Check that correct number of cards generated", expectedNumCards, addedNote.numberOfCards());
    // Now delete the note
    cr.delete(newNoteUri, null, null);
    try {
        addedNote.load();
        fail("Expected RuntimeException to be thrown when deleting note");
    } catch (RuntimeException e) {
    // Expect RuntimeException to be thrown when loading deleted note
    }
}
Also used : ContentValues(android.content.ContentValues) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Uri(android.net.Uri) ContentResolver(android.content.ContentResolver) Test(org.junit.Test)

Example 2 with DB

use of com.ichi2.libanki.DB in project AnkiChinaAndroid by ankichinateam.

the class ContentProviderTest method testInsertField.

/**
 * Check that inserting and removing a note into default deck works as expected
 */
@Test
public void testInsertField() throws Exception {
    // Get required objects for test
    final ContentResolver cr = InstrumentationRegistry.getInstrumentation().getTargetContext().getContentResolver();
    Collection col = getCol();
    Model model = StdModels.basicModel.add(col, BASIC_MODEL_NAME);
    long modelId = model.getLong("id");
    JSONArray initialFieldsArr = model.getJSONArray("flds");
    int initialFieldCount = initialFieldsArr.length();
    Uri noteTypeUri = ContentUris.withAppendedId(FlashCardsContract.Model.CONTENT_URI, modelId);
    ContentValues insertFieldValues = new ContentValues();
    insertFieldValues.put(FlashCardsContract.Model.FIELD_NAME, TEST_FIELD_NAME);
    Uri fieldUri = cr.insert(Uri.withAppendedPath(noteTypeUri, "fields"), insertFieldValues);
    assertNotNull("Check field uri", fieldUri);
    // Ensure that the changes are physically saved to the DB
    col = reopenCol();
    model = col.getModels().get(modelId);
    // Test the field is as expected
    long fieldId = ContentUris.parseId(fieldUri);
    assertEquals("Check field id", initialFieldCount, fieldId);
    assertNotNull("Check model", model);
    JSONArray fldsArr = model.getJSONArray("flds");
    assertEquals("Check fields length", initialFieldCount + 1, fldsArr.length());
    assertEquals("Check last field name", TEST_FIELD_NAME, fldsArr.getJSONObject(fldsArr.length() - 1).optString("name", ""));
    col.getModels().rem(model);
}
Also used : ContentValues(android.content.ContentValues) Model(com.ichi2.libanki.Model) JSONArray(com.ichi2.utils.JSONArray) Collection(com.ichi2.libanki.Collection) Uri(android.net.Uri) ContentResolver(android.content.ContentResolver) Test(org.junit.Test)

Example 3 with DB

use of com.ichi2.libanki.DB in project AnkiChinaAndroid by ankichinateam.

the class DatabaseErrorDialog method onCreateDialog.

@Override
public MaterialDialog onCreateDialog(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    int mType = getArguments().getInt("dialogType");
    Resources res = getResources();
    MaterialDialog.Builder builder = new MaterialDialog.Builder(getActivity());
    builder.cancelable(true).title(getTitle());
    boolean sqliteInstalled = false;
    try {
        sqliteInstalled = Runtime.getRuntime().exec("sqlite3 --version").waitFor() == 0;
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
    switch(mType) {
        case DIALOG_LOAD_FAILED:
            {
                // the activity
                return builder.cancelable(false).content(getMessage()).iconAttr(R.attr.dialogErrorIcon).positiveText(res.getString(R.string.error_handling_options)).negativeText(res.getString(R.string.close)).onPositive((inner_dialog, which) -> ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_ERROR_HANDLING)).onNegative((inner_dialog, which) -> exit()).show();
            }
        case DIALOG_DB_ERROR:
            {
                // Database Check failed to execute successfully; give user the option of either choosing from repair
                // options, submitting an error report, or closing the activity
                MaterialDialog dialog = builder.cancelable(false).content(getMessage()).iconAttr(R.attr.dialogErrorIcon).positiveText(res.getString(R.string.error_handling_options)).negativeText(res.getString(R.string.answering_error_report)).neutralText(res.getString(R.string.close)).onPositive((inner_dialog, which) -> ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_ERROR_HANDLING)).onNegative((inner_dialog, which) -> {
                    ((DeckPicker) getActivity()).sendErrorReport();
                    dismissAllDialogFragments();
                }).onNeutral((inner_dialog, which) -> exit()).show();
                dialog.getCustomView().findViewById(R.id.md_buttonDefaultNegative).setEnabled(((DeckPicker) getActivity()).hasErrorFiles());
                return dialog;
            }
        case DIALOG_ERROR_HANDLING:
            {
                // The user has asked to see repair options; allow them to choose one of the repair options or go back
                // to the previous dialog
                ArrayList<String> options = new ArrayList<>();
                ArrayList<Integer> values = new ArrayList<>();
                if (!((AnkiActivity) getActivity()).colIsOpen()) {
                    // retry
                    options.add(res.getString(R.string.backup_retry_opening));
                    values.add(0);
                } else {
                    // fix integrity
                    options.add(res.getString(R.string.check_db));
                    values.add(1);
                }
                // repair db with sqlite
                if (sqliteInstalled) {
                    options.add(res.getString(R.string.backup_error_menu_repair));
                    values.add(2);
                }
                // // restore from backup
                options.add(res.getString(R.string.backup_restore));
                values.add(3);
                // delete old collection and build new one
                options.add(res.getString(R.string.backup_full_sync_from_server));
                values.add(4);
                // delete old collection and build new one
                options.add(res.getString(R.string.backup_del_collection));
                values.add(5);
                String[] titles = new String[options.size()];
                mRepairValues = new int[options.size()];
                for (int i = 0; i < options.size(); i++) {
                    titles[i] = options.get(i);
                    mRepairValues[i] = values.get(i);
                }
                return builder.iconAttr(R.attr.dialogErrorIcon).negativeText(res.getString(R.string.dialog_cancel)).items(titles).itemsCallback((materialDialog, view, which, charSequence) -> {
                    switch(mRepairValues[which]) {
                        case 0:
                            ((DeckPicker) getActivity()).restartActivity();
                            return;
                        case 1:
                            ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_CONFIRM_DATABASE_CHECK);
                            return;
                        case 2:
                            ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_REPAIR_COLLECTION);
                            return;
                        case 3:
                            ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_RESTORE_BACKUP);
                            return;
                        case 4:
                            ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_FULL_SYNC_FROM_SERVER);
                            return;
                        case 5:
                            ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_NEW_COLLECTION);
                            return;
                        default:
                            throw new RuntimeException("Unknown dialog selection: " + mRepairValues[which]);
                    }
                }).show();
            }
        case DIALOG_REPAIR_COLLECTION:
            {
                // Allow user to run BackupManager.repairCollection()
                return builder.content(getMessage()).iconAttr(R.attr.dialogErrorIcon).positiveText(res.getString(R.string.dialog_positive_repair)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> {
                    ((DeckPicker) getActivity()).repairCollection();
                    dismissAllDialogFragments();
                }).show();
            }
        case DIALOG_RESTORE_BACKUP:
            {
                // Allow user to restore one of the backups
                String path = CollectionHelper.getInstance().getCollectionPath(getActivity());
                File[] files = BackupManager.getBackups(new File(path));
                mBackups = new File[files.length];
                for (int i = 0; i < files.length; i++) {
                    mBackups[i] = files[files.length - 1 - i];
                }
                if (mBackups.length == 0) {
                    builder.title(res.getString(R.string.backup_restore)).content(getMessage()).positiveText(res.getString(R.string.dialog_ok)).onPositive((inner_dialog, which) -> ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_ERROR_HANDLING));
                } else {
                    String[] dates = new String[mBackups.length];
                    for (int i = 0; i < mBackups.length; i++) {
                        dates[i] = mBackups[i].getName().replaceAll(".*-(\\d{4}-\\d{2}-\\d{2})-(\\d{2})-(\\d{2}).apkg", "$1 ($2:$3 h)");
                    }
                    builder.title(res.getString(R.string.backup_restore_select_title)).negativeText(res.getString(R.string.dialog_cancel)).onNegative((inner_dialog, which) -> dismissAllDialogFragments()).items(dates).itemsCallbackSingleChoice(dates.length, (materialDialog, view, which, charSequence) -> {
                        if (mBackups[which].length() > 0) {
                            // restore the backup if it's valid
                            ((DeckPicker) getActivity()).restoreFromBackup(mBackups[which].getPath());
                            dismissAllDialogFragments();
                        } else {
                            // otherwise show an error dialog
                            new MaterialDialog.Builder(getActivity()).title(R.string.backup_error).content(R.string.backup_invalid_file_error).positiveText(R.string.dialog_ok).build().show();
                        }
                        return true;
                    });
                }
                MaterialDialog materialDialog = builder.build();
                materialDialog.setOnKeyListener((dialog, keyCode, event) -> {
                    if (keyCode == KeyEvent.KEYCODE_BACK) {
                        Timber.i("DIALOG_RESTORE_BACKUP caught hardware back button");
                        dismissAllDialogFragments();
                        return true;
                    }
                    return false;
                });
                return materialDialog;
            }
        case DIALOG_NEW_COLLECTION:
            {
                // Allow user to create a new empty collection
                return builder.content(getMessage()).positiveText(res.getString(R.string.dialog_positive_create)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> {
                    CollectionHelper ch = CollectionHelper.getInstance();
                    Time time = ch.getTimeSafe(getContext());
                    ch.closeCollection(false, "DatabaseErrorDialog: Before Create New Collection");
                    String path1 = CollectionHelper.getCollectionPath(getActivity());
                    if (BackupManager.moveDatabaseToBrokenFolder(path1, false, time)) {
                        ((DeckPicker) getActivity()).restartActivity();
                    } else {
                        ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_LOAD_FAILED);
                    }
                }).show();
            }
        case DIALOG_CONFIRM_DATABASE_CHECK:
            {
                // Confirmation dialog for database check
                return builder.content(getMessage()).positiveText(res.getString(R.string.dialog_ok)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> {
                    ((DeckPicker) getActivity()).integrityCheck();
                    dismissAllDialogFragments();
                }).show();
            }
        case DIALOG_CONFIRM_RESTORE_BACKUP:
            {
                // Confirmation dialog for backup restore
                return builder.content(getMessage()).positiveText(res.getString(R.string.dialog_continue)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> ((DeckPicker) getActivity()).showDatabaseErrorDialog(DIALOG_RESTORE_BACKUP)).show();
            }
        case DIALOG_FULL_SYNC_FROM_SERVER:
            {
                // Allow user to do a full-sync from the server
                return builder.content(getMessage()).positiveText(res.getString(R.string.dialog_positive_overwrite)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((inner_dialog, which) -> {
                    ((DeckPicker) getActivity()).sync("download");
                    dismissAllDialogFragments();
                }).show();
            }
        case DIALOG_DB_LOCKED:
            {
                // If the database is locked, all we can do is ask the user to exit.
                return builder.content(getMessage()).positiveText(res.getString(R.string.close)).cancelable(false).onPositive((inner_dialog, which) -> exit()).show();
            }
        default:
            return null;
    }
}
Also used : DeckPicker(com.ichi2.anki.DeckPicker) Bundle(android.os.Bundle) KeyEvent(android.view.KeyEvent) BackupManager(com.ichi2.anki.BackupManager) R(com.ichi2.anki.R) IOException(java.io.IOException) Time(com.ichi2.libanki.utils.Time) CollectionHelper(com.ichi2.anki.CollectionHelper) File(java.io.File) Timber(timber.log.Timber) ArrayList(java.util.ArrayList) AnkiActivity(com.ichi2.anki.AnkiActivity) Message(android.os.Message) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) Resources(android.content.res.Resources) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) ArrayList(java.util.ArrayList) Time(com.ichi2.libanki.utils.Time) IOException(java.io.IOException) AnkiActivity(com.ichi2.anki.AnkiActivity) Resources(android.content.res.Resources) CollectionHelper(com.ichi2.anki.CollectionHelper) DeckPicker(com.ichi2.anki.DeckPicker) File(java.io.File)

Example 4 with DB

use of com.ichi2.libanki.DB in project AnkiChinaAndroid by ankichinateam.

the class CardContentProvider method buryOrSuspendCard.

private void buryOrSuspendCard(Collection col, AbstractSched sched, Card card, boolean bury) {
    try {
        DB db = col.getDb();
        db.getDatabase().beginTransaction();
        try {
            if (card != null) {
                if (bury) {
                    // bury
                    sched.buryCards(new long[] { card.getId() });
                } else {
                    // suspend
                    sched.suspendCards(new long[] { card.getId() });
                }
            }
            db.getDatabase().setTransactionSuccessful();
        } finally {
            db.getDatabase().endTransaction();
        }
    } catch (RuntimeException e) {
        Timber.e(e, "buryOrSuspendCard - RuntimeException on burying or suspending card");
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundBurySuspendCard");
        return;
    }
}
Also used : DB(com.ichi2.libanki.DB)

Example 5 with DB

use of com.ichi2.libanki.DB in project AnkiChinaAndroid by ankichinateam.

the class CardContentProvider method answerCard.

private void answerCard(Collection col, AbstractSched sched, Card cardToAnswer, @Consts.BUTTON_TYPE int ease, long timeTaken) {
    try {
        DB db = col.getDb();
        db.getDatabase().beginTransaction();
        try {
            if (cardToAnswer != null) {
                if (timeTaken != -1) {
                    cardToAnswer.setTimerStarted(col.getTime().intTime() - timeTaken / 1000);
                }
                sched.answerCard(cardToAnswer, ease);
            }
            db.getDatabase().setTransactionSuccessful();
        } finally {
            db.getDatabase().endTransaction();
        }
    } catch (RuntimeException e) {
        Timber.e(e, "answerCard - RuntimeException on answering card");
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundAnswerCard");
        return;
    }
}
Also used : DB(com.ichi2.libanki.DB)

Aggregations

File (java.io.File)19 JSONObject (com.ichi2.utils.JSONObject)18 Collection (com.ichi2.libanki.Collection)14 IOException (java.io.IOException)14 DB (com.ichi2.libanki.DB)13 FileNotFoundException (java.io.FileNotFoundException)13 ArrayList (java.util.ArrayList)11 JSONArray (com.ichi2.utils.JSONArray)10 Test (org.junit.Test)10 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)9 ContentValues (android.content.ContentValues)8 Resources (android.content.res.Resources)8 Uri (android.net.Uri)8 JSONException (com.ichi2.utils.JSONException)8 Cursor (android.database.Cursor)7 Model (com.ichi2.libanki.Model)7 ContentResolver (android.content.ContentResolver)6 FileInputStream (java.io.FileInputStream)6 SQLException (android.database.SQLException)4 BufferedInputStream (java.io.BufferedInputStream)4