Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import anki.collection.OpChanges
import com.ichi2.anki.AnkiDroidApp.Companion.sharedPreferencesTestingOverride
import com.ichi2.anki.analytics.UsageAnalytics
import com.ichi2.anki.browser.SharedPreferencesLastDeckIdRepository
import com.ichi2.anki.common.android.AnkiDroidApplication
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.annotations.LegacyNotifications
import com.ichi2.anki.common.annotations.NeedsTest
import com.ichi2.anki.common.coroutines.applicationScope
Expand Down Expand Up @@ -141,6 +143,7 @@ open class AnkiDroidApp :
}
}
instance = this
AnkiDroidApplication.setApplicationInstance(this)

// Get preferences
val preferences = this.sharedPrefs()
Expand Down Expand Up @@ -467,6 +470,9 @@ open class AnkiDroidApp :
isAccessible = true
set(field, null)
}
// Mirror reality: when AnkiDroidApp.onCreate doesn't run (the bmgr-restore
// scenario), appContext is also uninitialized.
AnkiDroidApplication.clearForTesting()
}

@VisibleForTesting(otherwise = VisibleForTesting.NONE)
Expand All @@ -477,6 +483,10 @@ open class AnkiDroidApp :
isAccessible = true
set(field, value)
}
// Production code (AnkiDroidApp.onCreate) sets appContext
// right after AnkiDroidApp.instance. Mirror that in tests so callers using the
// common-side accessor see the same mock.
AnkiDroidApplication.setApplicationInstance(value)
}

/** Load the libraries to allow access to Anki-Android-Backend */
Expand Down
2 changes: 1 addition & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ open class CardBrowser :
/**
* Implementation of `by viewModels()` for use in [onCreate]
*
* @see showedActivityFailedScreen - we may not have AnkiDroidApp.instance and therefore can't
* @see showedActivityFailedScreen - we may not have appContext and therefore can't
* create the ViewModel
*
* @param fragmented True if `noteEditorFrame` is non-null (x-large displays)
Expand Down
3 changes: 2 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/CardTemplateEditor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.android.input.ShortcutGroup
import com.ichi2.anki.android.input.shortcut
import com.ichi2.anki.cardviewer.SingleCardSide
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.annotations.NeedsTest
import com.ichi2.anki.common.utils.android.showThemedToast
import com.ichi2.anki.common.utils.annotation.KotlinCleanup
Expand Down Expand Up @@ -1277,7 +1278,7 @@ open class CardTemplateEditor : AnkiActivity(R.layout.activity_card_template_edi
}

private fun launchCardBrowserAppearance(currentTemplate: BackendCardTemplate) {
val context = AnkiDroidApp.instance.baseContext
val context = appContext
val browserAppearanceIntent = CardTemplateBrowserAppearanceEditor.getIntentFromTemplate(context, currentTemplate)
onCardBrowserAppearanceActivityResult.launch(browserAppearanceIntent)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import android.os.Parcel
import android.os.Parcelable
import androidx.core.os.bundleOf
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.annotations.NeedsTest
import com.ichi2.anki.compat.CompatHelper.Companion.compat
import com.ichi2.anki.compat.CompatHelper.Companion.getSerializableCompat
Expand Down Expand Up @@ -53,9 +54,10 @@ class CardTemplateNotetype(
var templateChanges = ArrayList<TemplateChange>()
private set

// TODO: cleanup applicationContext is not necessary, this is an Application
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

fun toBundle(): Bundle =
bundleOf(
INTENT_MODEL_FILENAME to saveTempNoteType(AnkiDroidApp.instance.applicationContext, notetype),
INTENT_MODEL_FILENAME to saveTempNoteType(appContext, notetype),
"mTemplateChanges" to templateChanges,
)

Expand Down Expand Up @@ -406,7 +408,7 @@ class CardTemplateNotetype(
/** Clear any temp note type files saved into internal cache directory */
fun clearTempNoteTypeFiles(): Int {
var deleteCount = 0
for (c in AnkiDroidApp.instance.cacheDir.listFiles() ?: arrayOf()) {
for (c in appContext.cacheDir.listFiles() ?: arrayOf()) {
val absolutePath = c.absolutePath
if (absolutePath.contains("editedTemplate") && absolutePath.endsWith("json")) {
if (!c.delete()) {
Expand Down
2 changes: 1 addition & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/CollectionHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ object CollectionHelper {
*
* @return the absolute path to the AnkiDroid directory.
*/
// This uses a lambda as we typically depends on the `lateinit` AnkiDroidApp.instance
// This uses a lambda as we typically depends on the `lateinit` appContext
// If we remove all Android references, we get a significant unit test speedup
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
internal fun getCurrentAnkiDroidDirectoryOptionalContext(
Expand Down
5 changes: 3 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/CollectionManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.CollectionManager.withOpenColOrNull
import com.ichi2.anki.CollectionManager.withQueue
import com.ichi2.anki.backend.createDatabaseUsingRustBackend
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.utils.android.isRobolectric
import com.ichi2.anki.libanki.Collection
import com.ichi2.anki.libanki.CollectionFiles
Expand Down Expand Up @@ -288,8 +289,8 @@ object CollectionManager {
}

fun getCollectionDirectory() =
// Allow execution if AnkiDroidApp.instance is not initialized
CollectionHelper.getCurrentAnkiDroidDirectoryOptionalContext(AnkiDroidApp.sharedPrefs()) { AnkiDroidApp.instance }
// Allow execution if appContext is not initialized
CollectionHelper.getCurrentAnkiDroidDirectoryOptionalContext(AnkiDroidApp.sharedPrefs()) { appContext }

/** Ensures the AnkiDroid directory is created, then returns the path to the
* folder and the name of the collection file inside it. */
Expand Down
5 changes: 3 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/DayRolloverHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import anki.collection.OpChanges
import anki.collection.opChanges
import com.ichi2.anki.CollectionManager.withOpenColOrNull
import com.ichi2.anki.android.AnkiBroadcastReceiver
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.coroutines.applicationScope
import com.ichi2.anki.common.crashreporting.CrashReportService
import com.ichi2.anki.common.exception.ManuallyReportedException
Expand Down Expand Up @@ -110,7 +111,7 @@ object DayRolloverHandler : AnkiBroadcastReceiver() {

Timber.i("day cutoff changed %d -> %d", lastCutoff, currentCutoff)
// Re-arm the wall-clock alarm whenever the cutoff changes
DayRolloverAlarm.scheduleNext(AnkiDroidApp.instance)
DayRolloverAlarm.scheduleNext(appContext)
// we do not want to send a "study queues changes" message initially
if (lastCutoff != null) {
handleDayRollover()
Expand All @@ -126,7 +127,7 @@ object DayRolloverHandler : AnkiBroadcastReceiver() {

Timber.i("day rollover: updating widgets")
try {
WidgetStatus.updateInBackground(AnkiDroidApp.instance)
WidgetStatus.updateInBackground(appContext)
} catch (e: Exception) {
Timber.w(e, "failed to update widgets")
}
Expand Down
3 changes: 2 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ import com.ichi2.anki.android.back.exitViaDoubleTapBackCallback
import com.ichi2.anki.android.input.ShortcutGroup
import com.ichi2.anki.android.input.shortcut
import com.ichi2.anki.android.view.locationInWindow
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.annotations.NeedsTest
import com.ichi2.anki.common.crashreporting.CrashReportService
import com.ichi2.anki.common.destinations.navigate
Expand Down Expand Up @@ -989,7 +990,7 @@ open class DeckPicker :
* @see DeckPickerViewModel.handleStartup
*/
private fun handleStartup() {
val context = AnkiDroidApp.instance
val context = appContext

val environment: AnkiDroidEnvironment =
object : AnkiDroidEnvironment {
Expand Down
3 changes: 2 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/JavaScriptTTS.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import android.os.Bundle
import android.speech.tts.TextToSpeech
import android.speech.tts.TextToSpeech.OnInitListener
import androidx.annotation.IntDef
import com.ichi2.anki.common.android.appContext

/**
* Since it is assumed that only advanced users will use the JavaScript api,
Expand Down Expand Up @@ -136,7 +137,7 @@ class JavaScriptTTS internal constructor() : OnInitListener {
}

init {
val context = AnkiDroidApp.instance.applicationContext
val context = appContext
tts = TextToSpeech(context, this)
}
}
6 changes: 3 additions & 3 deletions AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import com.ichi2.anki.OnContextAndLongClickListener.Companion.setOnContextAndLon
import com.ichi2.anki.android.input.ShortcutGroup
import com.ichi2.anki.android.input.ShortcutGroupProvider
import com.ichi2.anki.android.input.shortcut
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.annotations.NeedsTest
import com.ichi2.anki.common.crashreporting.CrashReportService
import com.ichi2.anki.common.utils.HashUtil
Expand Down Expand Up @@ -130,7 +131,6 @@ import com.ichi2.anki.multimedia.MultimediaResult
import com.ichi2.anki.multimedia.MultimediaResultContract
import com.ichi2.anki.multimedia.MultimediaUtils.createImageFile
import com.ichi2.anki.multimedia.MultimediaViewModel
import com.ichi2.anki.multimediacard.IMultimediaEditableNote
import com.ichi2.anki.multimediacard.impl.MultimediaEditableNote
import com.ichi2.anki.noteeditor.CustomToolbarButton
import com.ichi2.anki.noteeditor.FieldState
Expand Down Expand Up @@ -2730,7 +2730,7 @@ class NoteEditorFragment :
fun addNoteArgs(): Bundle = Bundle().apply { putInt(EXTRA_CALLER, NoteEditorCaller.DECKPICKER.value) }

fun shouldReplaceNewlines(): Boolean =
AnkiDroidApp.instance
appContext
.sharedPrefs()
.getBoolean(PREF_NOTE_EDITOR_NEWLINE_REPLACE, true)

Expand All @@ -2743,7 +2743,7 @@ class NoteEditorFragment :
}

private fun shouldHideToolbar(): Boolean =
!AnkiDroidApp.instance
!appContext
.sharedPrefs()
.getBoolean(PREF_NOTE_EDITOR_SHOW_TOOLBAR, true)
}
Expand Down
3 changes: 2 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/TtsVoices.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ package com.ichi2.anki

import android.speech.tts.TextToSpeech
import android.speech.tts.Voice
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.coroutines.applicationScope
import com.ichi2.anki.i18n.normalize
import com.ichi2.anki.i18n.toAnkiTwoLetterCode
Expand Down Expand Up @@ -202,7 +203,7 @@ object TtsVoices {
// TextToSpeech retains the context. So we can't give it any context that
// may be expected to disappear, as it would cause a memory leak. Hence
// we pass it the application as context.
TextToSpeech(AnkiDroidApp.instance) { status ->
TextToSpeech(appContext) { status ->
if (status == TextToSpeech.SUCCESS) {
Timber.v("TTS creation success")
ttsEngine = textToSpeech?.defaultEngine
Expand Down
3 changes: 2 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/Whiteboard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import androidx.annotation.CheckResult
import androidx.annotation.VisibleForTesting
import androidx.core.content.edit
import androidx.core.graphics.scale
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.annotations.NeedsTest
import com.ichi2.anki.common.time.Time
import com.ichi2.anki.common.time.getTimestamp
Expand Down Expand Up @@ -585,7 +586,7 @@ class Whiteboard(
}

private val displayDimensions: Point
get() = getDisplayDimensions(AnkiDroidApp.instance.applicationContext)
get() = getDisplayDimensions(appContext)
}

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.criticalay.GoogleAnalytics
import com.ichi2.anki.AnkiDroidApp
import com.ichi2.anki.BuildConfig
import com.ichi2.anki.R
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.annotations.NeedsTest
import com.ichi2.anki.common.utils.ext.getRootCause
import com.ichi2.anki.preferences.sharedPrefs
Expand Down Expand Up @@ -49,7 +49,7 @@ object AnkiDroidUsageAnalytics {

/**
* Application context captured during [initialize]. Held here so we don't
* rely on [AnkiDroidApp.instance] from background paths the singleton can
* rely on [appContext] from background paths the singleton can
* be uninitialized in rare Android scenarios (e.g. BackupManager) and
* analytics is a startup concern that must not crash.
*/
Expand Down Expand Up @@ -223,7 +223,7 @@ object AnkiDroidUsageAnalytics {
get() = optIn
set(value) {
optIn = value
AnkiDroidApp.instance.sharedPrefs().edit {
appContext.sharedPrefs().edit {
putBoolean(ANALYTICS_OPTIN_KEY, value)
}
// Rebuild the underlying client so its own `enabled` flag picks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ import com.brsanthu.googleanalytics.GoogleAnalytics
import com.brsanthu.googleanalytics.GoogleAnalyticsConfig
import com.brsanthu.googleanalytics.httpclient.OkHttpClientImpl
import com.brsanthu.googleanalytics.request.DefaultRequest
import com.ichi2.anki.AnkiDroidApp
import com.ichi2.anki.BuildConfig
import com.ichi2.anki.R
import com.ichi2.anki.analytics.AnalyticsConstants.reportablePrefKeys
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.utils.annotation.KotlinCleanup
import com.ichi2.anki.preferences.sharedPrefs
import com.ichi2.utils.DisplayUtils
Expand Down Expand Up @@ -190,7 +190,7 @@ object UsageAnalytics {
sAnalytics!!.flush()
sAnalytics = null
unInstallDefaultExceptionHandler()
initialize(AnkiDroidApp.instance.applicationContext)
initialize(appContext)
}

/**
Expand Down Expand Up @@ -306,12 +306,12 @@ object UsageAnalytics {
// A listener on this preference handles the rest
var isEnabled: Boolean
get() {
val userPrefs = AnkiDroidApp.instance.sharedPrefs()
val userPrefs = appContext.sharedPrefs()
return userPrefs.getBoolean(ANALYTICS_OPTIN_KEY, false)
}
set(value) {
// A listener on this preference handles the rest
AnkiDroidApp.instance.sharedPrefs().edit {
appContext.sharedPrefs().edit {
putBoolean(ANALYTICS_OPTIN_KEY, value)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import androidx.activity.OnBackPressedCallback
import androidx.preference.PreferenceManager
import com.google.android.material.snackbar.Snackbar
import com.ichi2.anki.AnkiActivity
import com.ichi2.anki.AnkiDroidApp
import com.ichi2.anki.R
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.utils.android.HandlerUtils
import com.ichi2.anki.settings.Prefs
import com.ichi2.anki.snackbar.showSnackbar
Expand Down Expand Up @@ -91,6 +91,6 @@ fun AnkiActivity.exitViaDoubleTapBackCallback(): OnBackPressedCallback =
}

PreferenceManager
.getDefaultSharedPreferences(AnkiDroidApp.instance)
.getDefaultSharedPreferences(appContext)
.registerOnSharedPreferenceChangeListener(callback.strongListenerReference)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package com.ichi2.anki.browser

import android.content.Context
import androidx.core.content.edit
import com.ichi2.anki.AnkiDroidApp
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.libanki.DeckId
import com.ichi2.anki.libanki.Decks

Expand All @@ -37,22 +37,22 @@ interface LastDeckIdRepository {
class SharedPreferencesLastDeckIdRepository : LastDeckIdRepository {
override var lastDeckId: DeckId?
get() =
AnkiDroidApp.instance
appContext
.getSharedPreferences(PERSISTENT_STATE_FILE, 0)
.getLong(LAST_DECK_ID_KEY, Decks.NOT_FOUND_DECK_ID)
.takeUnless { it == Decks.NOT_FOUND_DECK_ID }
set(value) =
if (value == null) {
clearLastDeckId()
} else {
AnkiDroidApp.instance.getSharedPreferences(PERSISTENT_STATE_FILE, 0).edit {
appContext.getSharedPreferences(PERSISTENT_STATE_FILE, 0).edit {
putLong(LAST_DECK_ID_KEY, value)
}
}

companion object {
fun clearLastDeckId() {
val context: Context = AnkiDroidApp.instance
val context: Context = appContext
context.getSharedPreferences(PERSISTENT_STATE_FILE, 0).edit {
remove(LAST_DECK_ID_KEY)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import androidx.annotation.VisibleForTesting
import com.ichi2.anki.AbstractFlashcardViewer.Companion.getMediaBaseUrl
import com.ichi2.anki.AndroidTtsError
import com.ichi2.anki.AndroidTtsPlayer
import com.ichi2.anki.AnkiDroidApp
import com.ichi2.anki.CollectionHelper.getMediaDirectory
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.cardviewer.MediaErrorBehavior.CONTINUE_MEDIA
import com.ichi2.anki.cardviewer.MediaErrorBehavior.RETRY_MEDIA
import com.ichi2.anki.cardviewer.MediaErrorBehavior.STOP_MEDIA
import com.ichi2.anki.common.android.appContext
import com.ichi2.anki.common.annotations.NeedsTest
import com.ichi2.anki.libanki.AvTag
import com.ichi2.anki.libanki.Card
Expand Down Expand Up @@ -98,7 +98,7 @@ class CardMediaPlayer : Closeable {
this.mediaErrorListener = mediaErrorListener
this.soundTagPlayer =
SoundTagPlayer(
soundUriBase = getMediaBaseUrl(getMediaDirectory(AnkiDroidApp.instance)),
soundUriBase = getMediaBaseUrl(getMediaDirectory(appContext)),
videoPlayer = VideoPlayer(javascriptEvaluator),
)
this.ttsPlayer = scope.async { AndroidTtsPlayer.createInstance(scope) }
Expand Down
Loading
Loading