So my app has multiple languages:
Currently I set Polish, and English is system default.
App's build.gradle.kts
:
android {
androidResources {
generateLocaleConfig = true
}
...
}
The following invisible activity is started from TileService
for Android 14+, which in turn starts a foreground service, because of the Google's failure (as usual):
class MyForegroundServiceStarterWithInvisibleThemeActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// start foreground service - MyForegroundService
finish()
}
}
It needs "Appear on top" permission (or others) of course, to be able to start activities from the background.
val Context.languageContext: Context
get() = ContextCompat.getContextForLanguage(this)
Service in which I need to get localized strings (for notifications, toasts, etc.):
@AndroidEntryPoint
class MyForegroundService : LifecycleService() {
private lateinit var context: Context
override fun onCreate() {
super.onCreate()
context = languageContext
Log.d("TEST", "languageContext at start: ${context.getString(R.string.default_text)}, isAppForeground: ${isAppInForegrounded()}")
lifecycleScope.launch {
while(true) {
delay(1000L)
Log.d("TEST", "languageContext: ${context.getString(R.string.default_text)}, isAppForeground: ${isAppInForegrounded()}")
}
}
}
}
fun isAppInForegrounded(): Boolean {
val appProcessInfo = ActivityManager.RunningAppProcessInfo()
ActivityManager.getMyMemoryState(appProcessInfo)
return appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|| appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE
}
And here's what I get when the app hasn’t been started for a while (its process wasn't running), cold start from QuickSettings:
15:12:43.610 D languageContext at start: Domyślny, isAppForeground: true
15:12:44.613 D languageContext: Default, isAppForeground: false // why does it return English (system default) now??? nonsense
15:12:45.633 D languageContext: Default, isAppForeground: false
15:12:46.634 D languageContext: Default, isAppForeground: false
15:12:47.636 D languageContext: Default, isAppForeground: false
15:12:48.639 D languageContext: Default, isAppForeground: false
15:12:49.641 D languageContext: Default, isAppForeground: false
15:12:50.645 D languageContext: Default, isAppForeground: false
15:12:53.018 D languageContext: Domyślny, isAppForeground: true
15:12:54.025 D languageContext: Domyślny, isAppForeground: true
15:12:55.026 D languageContext: Domyślny, isAppForeground: true
15:12:56.028 D languageContext: Domyślny, isAppForeground: true
15:12:57.030 D languageContext: Domyślny, isAppForeground: true
15:12:58.032 D languageContext: Domyślny, isAppForeground: true
15:12:59.032 D languageContext: Domyślny, isAppForeground: true
15:13:00.035 D languageContext: Domyślny, isAppForeground: true
15:13:01.069 D languageContext: Domyślny, isAppForeground: true
15:13:02.071 D languageContext: Domyślny, isAppForeground: false
15:13:03.073 D languageContext: Domyślny, isAppForeground: false
15:13:04.093 D languageContext: Domyślny, isAppForeground: false
15:13:05.094 D languageContext: Domyślny, isAppForeground: true
15:13:06.096 D languageContext: Domyślny, isAppForeground: true
15:13:07.105 D languageContext: Domyślny, isAppForeground: true
15:13:08.108 D languageContext: Domyślny, isAppForeground: true
15:13:09.109 D languageContext: Domyślny, isAppForeground: true
15:13:10.110 D languageContext: Domyślny, isAppForeground: true
15:13:11.111 D languageContext: Default, isAppForeground: false
15:13:12.112 D languageContext: Default, isAppForeground: false
15:13:13.115 D languageContext: Default, isAppForeground: false
For some reason, it switches to the default localization (English) instead of Polish after short time.
But when I open a visible activity while the service is still running (not interrupted and not restarted), it starts returning the overridden localization instead of the default one, as it should.
It doesn't make sense to me. Another bug?
Even if I try to call languageContext
each time I get string, it still be the default localization
Well I did this in an App about a year ago and it worked for me with the following code.
override fun attachBaseContext(newBase: Context?) {
newBase?.let {
super.attachBaseContext(ContextWrapper(it.setAppLanguage(currentAppLanguage(it))))
return
}
super.attachBaseContext(null)
}
private fun currentAppLanguage(context: Context): AppLanguage {
val sharedPreferences = SharedPreferencesManager.sharedPreferences(context)
val lastAppLanguageCode = sharedPreferences.getString(SharedPreferencesManager.lastAppLanguage, null) ?: Locale.getDefault().language
return AppLanguage.fromLanguageCode(lastAppLanguageCode)
}
private fun restartActivity() {
val restartIntent = Intent(this, this::class.java)
restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
finish()
startActivity(restartIntent)
}
The first two func's do the magic in forcing a language, if you call restartActivity it get's restarted in your preferred language.
Could you try it? Because it worked for me.... Hopefully it works for you too...
!!!!UPDATE BELOW!!!!
I am sorry, I didn't look for the Context Extension... You need the following Context Extension too...
fun Context.setAppLanguage(appLanguage: AppLanguage): Context {
val locale = Locale(appLanguage.languageCode, appLanguage.countryCode)
Locale.setDefault(locale)
val config = resources.configuration
config.setLocale(locale)
config.setLayoutDirection(locale)
return createConfigurationContext(config)
}
enum class AppLanguage(val languageCode: String, val countryCode: String) {
DE("de", "DE"),
EN("en", "US");
companion object {
fun fromLanguageCode(languageCode: String): AppLanguage {
if (languageCode.lowercase() == DE.languageCode.lowercase()) {
return DE
}
return EN
}
}
}