Reload extensions when relevant settings are updated (#3954)
This commit is contained in:
@@ -23,8 +23,12 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -70,8 +74,16 @@ class ExtensionManager(
|
||||
|
||||
init {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
initExtensions()
|
||||
loadExtensions()
|
||||
ExtensionInstallReceiver(InstallationListener()).register(context)
|
||||
|
||||
// Everything the load decision rests on can change while running, so decide again
|
||||
merge(
|
||||
trustExtension.changes(),
|
||||
preferences.enabledContentWarnings.changes().distinctUntilChanged().drop(1).map {},
|
||||
preferences.applyContentWarningsToInstalled.changes().distinctUntilChanged().drop(1).map {},
|
||||
)
|
||||
.collectLatest { loadExtensions() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,11 +136,13 @@ class ExtensionManager(
|
||||
fun getSourceData(id: Long) = availableExtensionsSourcesData[id]
|
||||
|
||||
/**
|
||||
* Loads and registers the installed extensions.
|
||||
* Loads and registers the installed extensions. Safe to call again: every extension is judged
|
||||
* again, so one can move between loaded and not loaded in either direction, while extensions
|
||||
* that still pass keep the instances they already had.
|
||||
*/
|
||||
private fun initExtensions() {
|
||||
private suspend fun loadExtensions() {
|
||||
try {
|
||||
val extensions = ExtensionLoader.loadExtensions(context)
|
||||
val extensions = ExtensionLoader.loadExtensions(context, loadedExtensionMapFlow.value)
|
||||
|
||||
loadedExtensionMapFlow.value = extensions
|
||||
.filterIsInstance<Extension.Loaded>()
|
||||
@@ -138,11 +152,13 @@ class ExtensionManager(
|
||||
.filterIsInstance<Extension.NotLoaded>()
|
||||
.associateBy { it.pkgName }
|
||||
|
||||
initialized.complete(Unit)
|
||||
// Newly loaded extensions have no status derived from the store index yet
|
||||
updatedInstalledExtensionsStatuses(availableExtensionMapFlow.value.values.toList())
|
||||
} catch (e: Throwable) {
|
||||
// Release anything waiting on the extensions before the failure propagates
|
||||
logcat(LogPriority.ERROR, e) { "Failed to load extensions" }
|
||||
} finally {
|
||||
// Release anything waiting on the extensions whether or not the load worked
|
||||
initialized.complete(Unit)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,19 +307,12 @@ class ExtensionManager(
|
||||
*
|
||||
* @param extension the extension to trust
|
||||
*/
|
||||
suspend fun trust(extension: Extension.NotLoaded) {
|
||||
fun trust(extension: Extension.NotLoaded) {
|
||||
val reason = extension.reason as? Extension.NotLoaded.Reason.Untrusted ?: return
|
||||
notLoadedExtensionMapFlow.value[extension.pkgName] ?: return
|
||||
|
||||
// Loading it again is left to the reload triggered by the trust change
|
||||
trustExtension.trust(extension.pkgName, extension.versionCode, reason.signatureHash)
|
||||
|
||||
notLoadedExtensionMapFlow.value -= extension.pkgName
|
||||
|
||||
when (val reloaded = ExtensionLoader.loadExtensionFromPkgName(context, extension.pkgName)) {
|
||||
is Extension.Loaded -> registerExtension(reloaded)
|
||||
is Extension.NotLoaded -> notLoadedExtensionMapFlow.value += reloaded
|
||||
null -> {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user