Skip to content

Commit

Permalink
Update to work with desktop 2.1.53 code
Browse files Browse the repository at this point in the history
Depends on ankidroid/Anki-Android-Backend#202

Due to the removal and change of a few backend methods, syncing, importing
and the card templates screen will not work when the schema16 setting is
active (actually schema18 now). To get them working again, those code
paths will need to switch to the backend implementations.

A few notes:
- Downgrading happens automatically when loading the collection in schema11
mode, so the extra code dealing with downgrades & "can downgrade" reporting
can be stripped.
- Added the ability to run col.set_config("key", JSONObject.NULL), as
unit tests were attempting to write the entire collection config, which is
no longer supported.
- All tests pass on both old and new backends, though the latter required
disabling a few failed tests when running with the new schema
(eg notetype updating).

Integrates, and thus closes ankidroid#11579 and closes ankidroid#11581
  • Loading branch information
dae committed Jun 16, 2022
1 parent 99eb2a2 commit 4ca5608
Show file tree
Hide file tree
Showing 50 changed files with 362 additions and 436 deletions.
22 changes: 22 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@
import com.ichi2.anki.services.BootService;
import com.ichi2.anki.services.NotificationService;
import com.ichi2.compat.CompatHelper;
import com.ichi2.libanki.backend.DroidBackend;
import com.ichi2.libanki.backend.RustDroidBackend;
import com.ichi2.libanki.backend.RustDroidV16Backend;
import com.ichi2.utils.AdaptionUtil;
import com.ichi2.utils.ExceptionUtil;
import com.ichi2.utils.LanguageUtil;
import com.ichi2.anki.analytics.UsageAnalytics;
import com.ichi2.utils.Permissions;

import net.ankiweb.rsdroid.BackendFactory;
import net.ankiweb.rsdroid.BackendV11Factory;
import net.ankiweb.rsdroid.BackendVNextFactory;
import net.ankiweb.rsdroid.RustCleanup;

import java.io.InputStream;
import java.util.Locale;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -492,4 +500,18 @@ protected void log(int priority, String tag, @NonNull String message, Throwable
}
}
}


/**
* Creates a backend instance using the currently configured backend implementation.
* @return
*/
@RustCleanup("Can remove after migrating to VNext")
public static BackendFactory currentBackendFactory() {
if (AnkiDroidApp.TESTING_USE_V16_BACKEND) {
return new BackendVNextFactory();
} else {
return new BackendV11Factory();
}
}
}
7 changes: 6 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/CollectionHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,12 @@ public static int getDatabaseVersion(Context context) throws UnknownDatabaseVers
} catch (Exception e) {
Timber.w(e, "Failed to query version");
// fallback to a pure DB implementation
return Storage.getDatabaseVersion(getCollectionPath(context));
int version = Storage.getDatabaseVersion(getCollectionPath(context));
if (version <= SCHEMA_DOWNGRADE_SUPPORTED_VERSION) {
// If the Rust call failed but the schema is in range, this indicates corruption.
throw new UnknownDatabaseVersionException(new Exception("probably corrupt"));
}
return version;
}
}

Expand Down
6 changes: 4 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/InitialActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import com.ichi2.anki.servicelayer.PreferenceUpgradeService
import com.ichi2.anki.servicelayer.PreferenceUpgradeService.setPreferencesUpToDate
import com.ichi2.utils.VersionUtils.pkgVersionName
import net.ankiweb.rsdroid.BackendException.BackendDbException.BackendDbLockedException
import net.ankiweb.rsdroid.BackendFactory
import net.ankiweb.rsdroid.RustBackendFailedException
import timber.log.Timber
import java.lang.ref.WeakReference
Expand Down Expand Up @@ -94,7 +93,10 @@ object InitialActivity {
val collectionPath = CollectionHelper.getCollectionPath(deckPicker)
require(backupManager.performDowngradeBackupInForeground(collectionPath)) { "backup failed" }
Timber.d("Downgrading database to V11: '%s'", collectionPath)
BackendFactory.createInstance().backend.downgradeBackend(collectionPath)
// TODO: this routine is no longer useful?
val backend = AnkiDroidApp.currentBackendFactory().getBackend()
backend.openCollection(collectionPath)
backend.closeCollection(true)
}

/** @return Whether any preferences were upgraded
Expand Down
6 changes: 6 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/ModelBrowser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import android.widget.AdapterView.OnItemLongClickListener
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AlertDialog
import com.afollestad.materialdialogs.DialogAction
import com.afollestad.materialdialogs.MaterialDialog
import com.ichi2.anim.ActivityTransitionAnimation
Expand Down Expand Up @@ -424,6 +425,11 @@ class ModelBrowser : AnkiActivity() {
* the user to edit the current note's templates.
*/
private fun openTemplateEditor() {
if (AnkiDroidApp.TESTING_USE_V16_BACKEND) {
// this screen needs rewriting for the new backend
AlertDialog.Builder(this).setTitle("Not yet supported on new backend").show()
return
}
val intent = Intent(this, CardTemplateEditor::class.java)
intent.putExtra("modelId", mCurrentID)
launchActivityForResultWithAnimation(intent, mEditTemplateResultLauncher, ActivityTransitionAnimation.Direction.START)
Expand Down
6 changes: 6 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/NoteEditor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.annotation.CheckResult
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatButton
import androidx.appcompat.widget.PopupMenu
import androidx.core.content.res.ResourcesCompat
Expand Down Expand Up @@ -1134,6 +1135,11 @@ class NoteEditor : AnkiActivity(), DeckSelectionListener, SubtitleListener, Tags
}

private fun showCardTemplateEditor() {
if (AnkiDroidApp.TESTING_USE_V16_BACKEND) {
// this screen needs rewriting for the new backend
AlertDialog.Builder(this).setTitle("Not yet supported on new backend").show()
return
}
val intent = Intent(this, CardTemplateEditor::class.java)
// Pass the model ID
intent.putExtra("modelId", currentlySelectedModel!!.getLong("id"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ internal constructor(
// set the preferences to the new deck path + checks CollectionHelper
// sets migration variables (migrationIsInProgress will be true)
updatePreferences(destinationPath)

// updatePreferences() opened the collection in the new location, which will have created
// a -wal file if the new backend code is active. Close it again, so that tests don't
// fail due to the presence of a -wal file in the destination folder.
if (AnkiDroidApp.TESTING_USE_V16_BACKEND) {
closeCollection()
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/async/CollectionTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.ichi2.libanki.sched.DeckTreeNode
import com.ichi2.libanki.sched.TreeNode
import com.ichi2.utils.*
import com.ichi2.utils.SyncStatus.Companion.ignoreDatabaseModification
import net.ankiweb.rsdroid.RustCleanup
import org.apache.commons.compress.archivers.zip.ZipFile
import timber.log.Timber
import java.io.File
Expand Down Expand Up @@ -553,6 +554,7 @@ open class CollectionTask<Progress, Result>(val task: TaskDelegateBase<Progress,
* A class allowing to send partial search result to the browser to display while the search ends
*/
@KotlinCleanup("move variables to constructor")
@RustCleanup("This provides little value since moving to the backend for DB access. Strip out?")
class PartialSearch(cards: List<CardCache>, columnIndex1: Int, columnIndex2: Int, numCardsToRender: Int, collectionTask: ProgressSenderAndCancelListener<List<CardCache>>, col: Collection) : ProgressSenderAndCancelListener<List<Long>> {
private val mCards: MutableList<CardCache>
private val mColumn1Index: Int
Expand Down
12 changes: 8 additions & 4 deletions AnkiDroid/src/main/java/com/ichi2/libanki/Collection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1255,24 +1255,23 @@ open class Collection @VisibleForTesting constructor(
*/
/** Return a list of card ids */
@KotlinCleanup("set reasonable defaults")
fun findCards(search: String?): List<Long> {
fun findCards(search: String): List<Long> {
return findCards(search, SortOrder.NoOrdering())
}

/**
* @return A list of card ids
* @throws com.ichi2.libanki.exception.InvalidSearchException Invalid search string
*/
fun findCards(search: String?, order: SortOrder): List<Long> {
fun findCards(search: String, order: SortOrder): List<Long> {
return Finder(this).findCards(search, order)
}

/**
* @return A list of card ids
* @throws com.ichi2.libanki.exception.InvalidSearchException Invalid search string
*/
@KotlinCleanup("non-null")
open fun findCards(search: String?, order: SortOrder, task: PartialSearch?): List<Long?>? {
open fun findCards(search: String, order: SortOrder, task: PartialSearch?): List<Long?>? {
return Finder(this).findCards(search, order, task)
}

Expand Down Expand Up @@ -2441,6 +2440,11 @@ open class Collection @VisibleForTesting constructor(
_config!!.put(key, value!!)
}

fun set_config(key: String, value: Any?) {
setMod()
_config!!.put(key, value)
}

fun remove_config(key: String) {
setMod()
_config!!.remove(key)
Expand Down
27 changes: 21 additions & 6 deletions AnkiDroid/src/main/java/com/ichi2/libanki/CollectionV16.kt
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,34 @@ class CollectionV16(
}
}

override fun render_output(c: Card, reload: Boolean, browser: Boolean): TemplateManager.TemplateRenderContext.TemplateRenderOutput {
override fun render_output(
c: Card,
reload: Boolean,
browser: Boolean
): TemplateManager.TemplateRenderContext.TemplateRenderOutput {
return TemplateManager.TemplateRenderContext.from_existing_card(c, browser).render()
}

override fun findCards(search: String?, order: SortOrder, task: CollectionTask.PartialSearch?): MutableList<Long> {
val result = try {
backend.backend.searchCards(search, order.toProtoBuf())
override fun findCards(
search: String,
order: SortOrder,
task: CollectionTask.PartialSearch?
): List<Long> {
val adjustedOrder = if (order is SortOrder.UseCollectionOrdering) {
@Suppress("DEPRECATION")
SortOrder.BuiltinSortKind(
get_config("sortType", null as String?) ?: "noteFld",
get_config("sortBackwards", false) ?: false,
)
} else {
order
}
val cardIdsList = try {
backend.backend.searchCards(search, adjustedOrder.toProtoBuf())
} catch (e: BackendInvalidInputException) {
throw InvalidSearchException(e)
}

val cardIdsList = result.cardIdsList

task?.doProgress(cardIdsList)
return cardIdsList
}
Expand Down
4 changes: 4 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/libanki/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ class Config(configStr: String) : ConfigManager() {
json.put(key, value)
}

override fun put(key: String, value: Any?) {
json.put(key, value)
}

override fun remove(key: String) {
json.remove(key)
}
Expand Down
1 change: 1 addition & 0 deletions AnkiDroid/src/main/java/com/ichi2/libanki/ConfigManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ abstract class ConfigManager {
abstract fun put(key: String, value: String)
abstract fun put(key: String, value: JSONArray)
abstract fun put(key: String, value: JSONObject)
abstract fun put(key: String, value: Any?)

abstract fun remove(key: String)

Expand Down
6 changes: 5 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/libanki/ConfigV16.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,15 @@ class ConfigV16(val backend: RustConfigBackend) : ConfigManager() {
backend.set(key, value)
}

override fun put(key: String, value: Any?) {
backend.set(key, value)
}

override fun remove(key: String) {
backend.remove(key)
}

override var json: JSONObject
get() = backend.getJson() as JSONObject
set(value) { backend.setJson(value) }
set(@Suppress("UNUSED_PARAMETER") value) { TODO("not implemented; use backend syncing") }
}
8 changes: 2 additions & 6 deletions AnkiDroid/src/main/java/com/ichi2/libanki/Consts.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package com.ichi2.libanki

import androidx.annotation.IntDef
import net.ankiweb.rsdroid.RustCleanup
import kotlin.annotation.Retention

object Consts {
Expand Down Expand Up @@ -109,17 +108,14 @@ object Consts {
var SCHEMA_VERSION = 11

/** The database schema version that we can downgrade from */
const val SCHEMA_DOWNGRADE_SUPPORTED_VERSION = 16
const val SCHEMA_DOWNGRADE_SUPPORTED_VERSION = 18
const val SYNC_MAX_BYTES = (2.5 * 1024 * 1024).toInt()
const val SYNC_MAX_FILES = 25
const val SYNC_BASE = "https://sync%s.ankiweb.net/"
@JvmField
val DEFAULT_HOST_NUM: Int? = null

/* Note: 10 if using Rust backend, 9 if using Java. Set in BackendFactory.getInstance */
@JvmField
@RustCleanup("Use 10")
var SYNC_VER = 9
const val SYNC_VER = 10

// Leech actions
const val LEECH_SUSPEND = 0
Expand Down
14 changes: 12 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/libanki/DB.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import com.ichi2.anki.dialogs.DatabaseErrorDialog;
import com.ichi2.utils.DatabaseChangeDecorator;

import net.ankiweb.rsdroid.BackendException;

import org.intellij.lang.annotations.Language;

import java.util.ArrayList;
Expand Down Expand Up @@ -77,9 +79,17 @@ public DB(@NonNull String ankiFilename, @Nullable OpenHelperFactory openHelperFa
.build();
SupportSQLiteOpenHelper helper = getSqliteOpenHelperFactory(openHelperFactory).create(configuration);
// Note: This line creates the database and schema when executed using a Rust backend
mDatabase = new DatabaseChangeDecorator(helper.getWritableDatabase());
try {
mDatabase = new DatabaseChangeDecorator(helper.getWritableDatabase());
} catch (BackendException.BackendDbException exc) {
throw exc.toSQLiteException("db open");
}
// No-op except when using the old Java backend
mDatabase.disableWriteAheadLogging();
mDatabase.query("PRAGMA synchronous = 2", null);
if (!AnkiDroidApp.TESTING_USE_V16_BACKEND) {
// full sync is not required when using a WAL
mDatabase.query("PRAGMA synchronous = 2", null);
}
mMod = false;
}

Expand Down
22 changes: 16 additions & 6 deletions AnkiDroid/src/main/java/com/ichi2/libanki/DecksV16.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import java8.util.Optional
import net.ankiweb.rsdroid.RustCleanup
import timber.log.Timber
import java.util.*
import BackendProto.Backend as pb

// legacy code may pass this in as the type argument to .id()
const val defaultDeck = 0
Expand Down Expand Up @@ -249,8 +248,7 @@ class DecksV16(private val col: Collection, private val decksBackend: DecksBacke

val deck = this.new_deck_legacy(type != 0)
deck.name = name
this.update(deck, preserve_usn = false)

deck.id = decksBackend.addDeckLegacy(deck)
return Optional.of(deck.id)
}

Expand Down Expand Up @@ -289,11 +287,23 @@ class DecksV16(private val col: Collection, private val decksBackend: DecksBacke
return decksBackend.all_decks_legacy()
}
fun new_deck_legacy(filtered: bool): DeckV16 {
return decksBackend.new_deck_legacy(filtered)
val deck = decksBackend.new_deck_legacy(filtered)
if (filtered) {
// until migrating to the dedicated method for creating filtered decks,
// we need to ensure the default config matches legacy expectations
val json = deck.getJsonObject()
val terms = json.getJSONArray("terms").getJSONArray(0)
terms.put(0, "")
terms.put(2, 0)
json.put("terms", JSONArray(listOf(terms)))
json.put("browserCollapsed", false)
json.put("collapsed", false)
}
return deck
}

fun deck_tree(): DeckTreeNode {
return decksBackend.deck_tree(now = 0L, top_deck_id = 0L)
return decksBackend.deck_tree(now = 0L)
}

/** All decks. Expensive; prefer all_names_and_ids() */
Expand Down Expand Up @@ -636,7 +646,7 @@ class DecksV16(private val col: Collection, private val decksBackend: DecksBacke
companion object {

@JvmStatic
fun find_deck_in_tree(node: pb.DeckTreeNode, deck_id: did): Optional<pb.DeckTreeNode> {
fun find_deck_in_tree(node: anki.decks.DeckTreeNode, deck_id: did): Optional<anki.decks.DeckTreeNode> {
if (node.deckId == deck_id) {
return Optional.of(node)
}
Expand Down
4 changes: 2 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/libanki/ModelsV16.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import com.ichi2.libanki.backend.NoteTypeNameIDUseCount
import com.ichi2.libanki.utils.*
import com.ichi2.utils.JSONArray
import com.ichi2.utils.JSONObject
import net.ankiweb.rsdroid.BackendV1
import net.ankiweb.rsdroid.Backend
import net.ankiweb.rsdroid.RustCleanup
import net.ankiweb.rsdroid.exceptions.BackendNotFoundException
import timber.log.Timber
Expand Down Expand Up @@ -102,7 +102,7 @@ var NoteType.type: Int
put("type", value)
}

class ModelsV16(col: Collection, backend: BackendV1) : ModelManager(col) {
class ModelsV16(col: Collection, backend: Backend) : ModelManager(col) {
/*
# Saving/loading registry
#############################################################
Expand Down
Loading

0 comments on commit 4ca5608

Please sign in to comment.