Skip to content

Commit ee10d2c

Browse files
committed
refactor: extract AnkiDroidApp.instance to :common:android as AnkiDroidApplication
Adds a top-level `appContext: Context` accessor in :common:android, set during AnkiDroidApp.onCreate() via AnkiDroidApplication.setApplicationInstance. Shared and feature-module code can now reach the Application context without depending on :AnkiDroid's AnkiDroidApp subclass.
1 parent c3ee85e commit ee10d2c

33 files changed

Lines changed: 133 additions & 62 deletions

AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import anki.collection.OpChanges
3636
import com.ichi2.anki.AnkiDroidApp.Companion.sharedPreferencesTestingOverride
3737
import com.ichi2.anki.analytics.UsageAnalytics
3838
import com.ichi2.anki.browser.SharedPreferencesLastDeckIdRepository
39+
import com.ichi2.anki.common.android.AnkiDroidApplication
40+
import com.ichi2.anki.common.android.appContext
3941
import com.ichi2.anki.common.annotations.LegacyNotifications
4042
import com.ichi2.anki.common.annotations.NeedsTest
4143
import com.ichi2.anki.common.coroutines.applicationScope
@@ -141,6 +143,7 @@ open class AnkiDroidApp :
141143
}
142144
}
143145
instance = this
146+
AnkiDroidApplication.setApplicationInstance(this)
144147

145148
// Get preferences
146149
val preferences = this.sharedPrefs()
@@ -467,6 +470,9 @@ open class AnkiDroidApp :
467470
isAccessible = true
468471
set(field, null)
469472
}
473+
// Mirror reality: when AnkiDroidApp.onCreate doesn't run (the bmgr-restore
474+
// scenario), appContext is also uninitialized.
475+
AnkiDroidApplication.clearForTesting()
470476
}
471477

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

482492
/** Load the libraries to allow access to Anki-Android-Backend */

AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ open class CardBrowser :
676676
/**
677677
* Implementation of `by viewModels()` for use in [onCreate]
678678
*
679-
* @see showedActivityFailedScreen - we may not have AnkiDroidApp.instance and therefore can't
679+
* @see showedActivityFailedScreen - we may not have appContext and therefore can't
680680
* create the ViewModel
681681
*
682682
* @param fragmented True if `noteEditorFrame` is non-null (x-large displays)

AnkiDroid/src/main/java/com/ichi2/anki/CardTemplateEditor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import com.ichi2.anki.CollectionManager.withCol
6363
import com.ichi2.anki.android.input.ShortcutGroup
6464
import com.ichi2.anki.android.input.shortcut
6565
import com.ichi2.anki.cardviewer.SingleCardSide
66+
import com.ichi2.anki.common.android.appContext
6667
import com.ichi2.anki.common.annotations.NeedsTest
6768
import com.ichi2.anki.common.utils.android.showThemedToast
6869
import com.ichi2.anki.common.utils.annotation.KotlinCleanup
@@ -1277,7 +1278,7 @@ open class CardTemplateEditor : AnkiActivity(R.layout.activity_card_template_edi
12771278
}
12781279

12791280
private fun launchCardBrowserAppearance(currentTemplate: BackendCardTemplate) {
1280-
val context = AnkiDroidApp.instance.baseContext
1281+
val context = appContext
12811282
val browserAppearanceIntent = CardTemplateBrowserAppearanceEditor.getIntentFromTemplate(context, currentTemplate)
12821283
onCardBrowserAppearanceActivityResult.launch(browserAppearanceIntent)
12831284
}

AnkiDroid/src/main/java/com/ichi2/anki/CardTemplateNotetype.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.os.Parcel
2222
import android.os.Parcelable
2323
import androidx.core.os.bundleOf
2424
import com.ichi2.anki.CollectionManager.withCol
25+
import com.ichi2.anki.common.android.appContext
2526
import com.ichi2.anki.common.annotations.NeedsTest
2627
import com.ichi2.anki.compat.CompatHelper.Companion.compat
2728
import com.ichi2.anki.compat.CompatHelper.Companion.getSerializableCompat
@@ -53,9 +54,10 @@ class CardTemplateNotetype(
5354
var templateChanges = ArrayList<TemplateChange>()
5455
private set
5556

57+
// TODO: cleanup applicationContext is not necessary, this is an Application
5658
fun toBundle(): Bundle =
5759
bundleOf(
58-
INTENT_MODEL_FILENAME to saveTempNoteType(AnkiDroidApp.instance.applicationContext, notetype),
60+
INTENT_MODEL_FILENAME to saveTempNoteType(appContext, notetype),
5961
"mTemplateChanges" to templateChanges,
6062
)
6163

@@ -406,7 +408,7 @@ class CardTemplateNotetype(
406408
/** Clear any temp note type files saved into internal cache directory */
407409
fun clearTempNoteTypeFiles(): Int {
408410
var deleteCount = 0
409-
for (c in AnkiDroidApp.instance.cacheDir.listFiles() ?: arrayOf()) {
411+
for (c in appContext.cacheDir.listFiles() ?: arrayOf()) {
410412
val absolutePath = c.absolutePath
411413
if (absolutePath.contains("editedTemplate") && absolutePath.endsWith("json")) {
412414
if (!c.delete()) {

AnkiDroid/src/main/java/com/ichi2/anki/CollectionHelper.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ object CollectionHelper {
288288
*
289289
* @return the absolute path to the AnkiDroid directory.
290290
*/
291-
// This uses a lambda as we typically depends on the `lateinit` AnkiDroidApp.instance
291+
// This uses a lambda as we typically depends on the `lateinit` appContext
292292
// If we remove all Android references, we get a significant unit test speedup
293293
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
294294
internal fun getCurrentAnkiDroidDirectoryOptionalContext(

AnkiDroid/src/main/java/com/ichi2/anki/CollectionManager.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.ichi2.anki.CollectionManager.withCol
3131
import com.ichi2.anki.CollectionManager.withOpenColOrNull
3232
import com.ichi2.anki.CollectionManager.withQueue
3333
import com.ichi2.anki.backend.createDatabaseUsingRustBackend
34+
import com.ichi2.anki.common.android.appContext
3435
import com.ichi2.anki.common.utils.android.isRobolectric
3536
import com.ichi2.anki.libanki.Collection
3637
import com.ichi2.anki.libanki.CollectionFiles
@@ -288,8 +289,8 @@ object CollectionManager {
288289
}
289290

290291
fun getCollectionDirectory() =
291-
// Allow execution if AnkiDroidApp.instance is not initialized
292-
CollectionHelper.getCurrentAnkiDroidDirectoryOptionalContext(AnkiDroidApp.sharedPrefs()) { AnkiDroidApp.instance }
292+
// Allow execution if appContext is not initialized
293+
CollectionHelper.getCurrentAnkiDroidDirectoryOptionalContext(AnkiDroidApp.sharedPrefs()) { appContext }
293294

294295
/** Ensures the AnkiDroid directory is created, then returns the path to the
295296
* folder and the name of the collection file inside it. */

AnkiDroid/src/main/java/com/ichi2/anki/DayRolloverHandler.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import anki.collection.OpChanges
3535
import anki.collection.opChanges
3636
import com.ichi2.anki.CollectionManager.withOpenColOrNull
3737
import com.ichi2.anki.android.AnkiBroadcastReceiver
38+
import com.ichi2.anki.common.android.appContext
3839
import com.ichi2.anki.common.coroutines.applicationScope
3940
import com.ichi2.anki.common.crashreporting.CrashReportService
4041
import com.ichi2.anki.common.exception.ManuallyReportedException
@@ -110,7 +111,7 @@ object DayRolloverHandler : AnkiBroadcastReceiver() {
110111

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

127128
Timber.i("day rollover: updating widgets")
128129
try {
129-
WidgetStatus.updateInBackground(AnkiDroidApp.instance)
130+
WidgetStatus.updateInBackground(appContext)
130131
} catch (e: Exception) {
131132
Timber.w(e, "failed to update widgets")
132133
}

AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ import com.ichi2.anki.android.back.exitViaDoubleTapBackCallback
102102
import com.ichi2.anki.android.input.ShortcutGroup
103103
import com.ichi2.anki.android.input.shortcut
104104
import com.ichi2.anki.android.view.locationInWindow
105+
import com.ichi2.anki.common.android.appContext
105106
import com.ichi2.anki.common.annotations.NeedsTest
106107
import com.ichi2.anki.common.crashreporting.CrashReportService
107108
import com.ichi2.anki.common.destinations.navigate
@@ -989,7 +990,7 @@ open class DeckPicker :
989990
* @see DeckPickerViewModel.handleStartup
990991
*/
991992
private fun handleStartup() {
992-
val context = AnkiDroidApp.instance
993+
val context = appContext
993994

994995
val environment: AnkiDroidEnvironment =
995996
object : AnkiDroidEnvironment {

AnkiDroid/src/main/java/com/ichi2/anki/JavaScriptTTS.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import android.os.Bundle
2020
import android.speech.tts.TextToSpeech
2121
import android.speech.tts.TextToSpeech.OnInitListener
2222
import androidx.annotation.IntDef
23+
import com.ichi2.anki.common.android.appContext
2324

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

138139
init {
139-
val context = AnkiDroidApp.instance.applicationContext
140+
val context = appContext
140141
tts = TextToSpeech(context, this)
141142
}
142143
}

AnkiDroid/src/main/java/com/ichi2/anki/NoteEditorFragment.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ import com.ichi2.anki.OnContextAndLongClickListener.Companion.setOnContextAndLon
8989
import com.ichi2.anki.android.input.ShortcutGroup
9090
import com.ichi2.anki.android.input.ShortcutGroupProvider
9191
import com.ichi2.anki.android.input.shortcut
92+
import com.ichi2.anki.common.android.appContext
9293
import com.ichi2.anki.common.annotations.NeedsTest
9394
import com.ichi2.anki.common.crashreporting.CrashReportService
9495
import com.ichi2.anki.common.utils.HashUtil
@@ -130,7 +131,6 @@ import com.ichi2.anki.multimedia.MultimediaResult
130131
import com.ichi2.anki.multimedia.MultimediaResultContract
131132
import com.ichi2.anki.multimedia.MultimediaUtils.createImageFile
132133
import com.ichi2.anki.multimedia.MultimediaViewModel
133-
import com.ichi2.anki.multimediacard.IMultimediaEditableNote
134134
import com.ichi2.anki.multimediacard.impl.MultimediaEditableNote
135135
import com.ichi2.anki.noteeditor.CustomToolbarButton
136136
import com.ichi2.anki.noteeditor.FieldState
@@ -2730,7 +2730,7 @@ class NoteEditorFragment :
27302730
fun addNoteArgs(): Bundle = Bundle().apply { putInt(EXTRA_CALLER, NoteEditorCaller.DECKPICKER.value) }
27312731

27322732
fun shouldReplaceNewlines(): Boolean =
2733-
AnkiDroidApp.instance
2733+
appContext
27342734
.sharedPrefs()
27352735
.getBoolean(PREF_NOTE_EDITOR_NEWLINE_REPLACE, true)
27362736

@@ -2743,7 +2743,7 @@ class NoteEditorFragment :
27432743
}
27442744

27452745
private fun shouldHideToolbar(): Boolean =
2746-
!AnkiDroidApp.instance
2746+
!appContext
27472747
.sharedPrefs()
27482748
.getBoolean(PREF_NOTE_EDITOR_SHOW_TOOLBAR, true)
27492749
}

0 commit comments

Comments
 (0)