145 lines
5.6 KiB
Kotlin
145 lines
5.6 KiB
Kotlin
package com.fsck.k9
|
|
|
|
import android.app.Application
|
|
import android.content.res.Configuration
|
|
import android.content.res.Resources
|
|
import app.k9mail.ui.widget.list.MessageListWidgetManager
|
|
import com.fsck.k9.activity.LauncherShortcuts
|
|
import com.fsck.k9.activity.MessageCompose
|
|
import com.fsck.k9.controller.MessagingController
|
|
import com.fsck.k9.job.WorkManagerConfigurationProvider
|
|
import com.fsck.k9.notification.NotificationChannelManager
|
|
import com.fsck.k9.provider.UnreadWidgetProvider
|
|
import com.fsck.k9.ui.base.AppLanguageManager
|
|
import com.fsck.k9.ui.base.ThemeManager
|
|
import com.fsck.k9.ui.base.extensions.currentLocale
|
|
import com.fsck.k9.widget.list.MessageListWidgetProvider
|
|
import java.util.Locale
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.GlobalScope
|
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
import kotlinx.coroutines.flow.drop
|
|
import kotlinx.coroutines.flow.launchIn
|
|
import kotlinx.coroutines.flow.onEach
|
|
import kotlinx.coroutines.plus
|
|
import org.koin.android.ext.android.inject
|
|
import timber.log.Timber
|
|
import androidx.work.Configuration as WorkManagerConfiguration
|
|
|
|
class App : Application(), WorkManagerConfiguration.Provider {
|
|
private val messagingController: MessagingController by inject()
|
|
private val messagingListenerProvider: MessagingListenerProvider by inject()
|
|
private val themeManager: ThemeManager by inject()
|
|
private val appLanguageManager: AppLanguageManager by inject()
|
|
private val notificationChannelManager: NotificationChannelManager by inject()
|
|
private val messageListWidgetManager: MessageListWidgetManager by inject()
|
|
private val workManagerConfigurationProvider: WorkManagerConfigurationProvider by inject()
|
|
|
|
private val appCoroutineScope: CoroutineScope = GlobalScope + Dispatchers.Main
|
|
private var appLanguageManagerInitialized = false
|
|
|
|
override fun onCreate() {
|
|
Core.earlyInit()
|
|
|
|
super.onCreate()
|
|
|
|
DI.start(this, coreModules + uiModules + appModules)
|
|
|
|
K9.init(this)
|
|
Core.init(this)
|
|
initializeAppLanguage()
|
|
updateNotificationChannelsOnAppLanguageChanges()
|
|
themeManager.init()
|
|
messageListWidgetManager.init()
|
|
|
|
messagingListenerProvider.listeners.forEach { listener ->
|
|
messagingController.addListener(listener)
|
|
}
|
|
}
|
|
|
|
private fun initializeAppLanguage() {
|
|
appLanguageManager.init()
|
|
applyOverrideLocaleToConfiguration()
|
|
appLanguageManagerInitialized = true
|
|
listenForAppLanguageChanges()
|
|
}
|
|
|
|
private fun applyOverrideLocaleToConfiguration() {
|
|
appLanguageManager.getOverrideLocale()?.let { overrideLocale ->
|
|
updateConfigurationWithLocale(superResources.configuration, overrideLocale)
|
|
}
|
|
}
|
|
|
|
private fun listenForAppLanguageChanges() {
|
|
appLanguageManager.overrideLocale
|
|
.drop(1) // We already applied the initial value
|
|
.onEach { overrideLocale ->
|
|
val locale = overrideLocale ?: Locale.getDefault()
|
|
updateConfigurationWithLocale(superResources.configuration, locale)
|
|
}
|
|
.launchIn(appCoroutineScope)
|
|
}
|
|
|
|
override fun onConfigurationChanged(newConfiguration: Configuration) {
|
|
applyOverrideLocaleToConfiguration()
|
|
super.onConfigurationChanged(superResources.configuration)
|
|
}
|
|
|
|
private fun updateConfigurationWithLocale(configuration: Configuration, locale: Locale) {
|
|
Timber.d("Updating application configuration with locale '$locale'")
|
|
|
|
val newConfiguration = Configuration(configuration).apply {
|
|
currentLocale = locale
|
|
}
|
|
|
|
@Suppress("DEPRECATION")
|
|
superResources.updateConfiguration(newConfiguration, superResources.displayMetrics)
|
|
}
|
|
|
|
private val superResources: Resources
|
|
get() = super.getResources()
|
|
|
|
// Creating a WebView instance triggers something that will cause the configuration of the Application's Resources
|
|
// instance to be reset to the default, i.e. not containing our locale override. Unfortunately, we're not notified
|
|
// about this event. So we're checking each time someone asks for the Resources instance whether we need to change
|
|
// the configuration again. Luckily, right now (Android 11), the platform is calling this method right after
|
|
// resetting the configuration.
|
|
override fun getResources(): Resources {
|
|
val resources = super.getResources()
|
|
|
|
if (appLanguageManagerInitialized) {
|
|
appLanguageManager.getOverrideLocale()?.let { overrideLocale ->
|
|
if (resources.configuration.currentLocale != overrideLocale) {
|
|
Timber.w("Resources configuration was reset. Re-applying locale override.")
|
|
appLanguageManager.applyOverrideLocale()
|
|
applyOverrideLocaleToConfiguration()
|
|
}
|
|
}
|
|
}
|
|
|
|
return resources
|
|
}
|
|
|
|
private fun updateNotificationChannelsOnAppLanguageChanges() {
|
|
appLanguageManager.appLocale
|
|
.distinctUntilChanged()
|
|
.onEach { notificationChannelManager.updateChannels() }
|
|
.launchIn(appCoroutineScope)
|
|
}
|
|
|
|
override fun getWorkManagerConfiguration(): WorkManagerConfiguration {
|
|
return workManagerConfigurationProvider.getConfiguration()
|
|
}
|
|
|
|
companion object {
|
|
val appConfig = AppConfig(
|
|
componentsToDisable = listOf(
|
|
MessageCompose::class.java,
|
|
LauncherShortcuts::class.java,
|
|
UnreadWidgetProvider::class.java,
|
|
MessageListWidgetProvider::class.java
|
|
)
|
|
)
|
|
}
|
|
}
|