From 559cf54798a935b2e049e2b6a6ba68563e7ca006 Mon Sep 17 00:00:00 2001 From: Elise Richards Date: Tue, 23 Mar 2021 13:16:30 -0500 Subject: [PATCH] For #17190: notifications are updated when locale is changed (#18179) * Add intent processor for locale changes * Recreate notification and notify in the service * Use locale use cases to update notification * Use notification id instead of tag * Add locale use cases and restore locale in application * Send locale to service instead of string * Controller tests for locale * Update Android Components version to 74.0.20210323143308 Co-authored-by: Arturo Mejia --- .../org/mozilla/fenix/FenixApplication.kt | 5 +++ .../org/mozilla/fenix/components/UseCases.kt | 6 ++++ .../session/PrivateNotificationService.kt | 26 ++++++++++++-- .../DefaultLocaleSettingsController.kt | 8 +++-- .../advanced/LocaleSettingsFragment.kt | 14 +++++--- .../advanced/LocaleSettingsControllerTest.kt | 34 +++++++++++++------ buildSrc/src/main/java/AndroidComponents.kt | 2 +- 7 files changed, 74 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt index e996309c1..3b0c50f1a 100644 --- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt +++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt @@ -165,6 +165,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { initializeWebExtensionSupport() restoreBrowserState() restoreDownloads() + restoreLocale() // Just to make sure it is impossible for any application-services pieces // to invoke parts of itself that require complete megazord initialization @@ -213,6 +214,10 @@ open class FenixApplication : LocaleAwareApplication(), Provider { components.useCases.downloadUseCases.restoreDownloads() } + private fun restoreLocale() { + components.useCases.localeUseCases.restore() + } + private fun initVisualCompletenessQueueAndQueueTasks() { val queue = components.performance.visualCompletenessQueue.queue diff --git a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt index 956cda377..9249c8ab8 100644 --- a/app/src/main/java/org/mozilla/fenix/components/UseCases.kt +++ b/app/src/main/java/org/mozilla/fenix/components/UseCases.kt @@ -22,6 +22,7 @@ import mozilla.components.feature.tabs.CustomTabsUseCases import mozilla.components.feature.tabs.TabsUseCases import mozilla.components.feature.top.sites.TopSitesStorage import mozilla.components.feature.top.sites.TopSitesUseCases +import mozilla.components.support.locale.LocaleUseCases import org.mozilla.fenix.perf.lazyMonitored import org.mozilla.fenix.utils.Mockable @@ -88,4 +89,9 @@ class UseCases( * Use cases that provide top sites management. */ val topSitesUseCase by lazyMonitored { TopSitesUseCases(topSitesStorage) } + + /** + * Use cases that handle locale management. + */ + val localeUseCases by lazyMonitored { LocaleUseCases(store) } } diff --git a/app/src/main/java/org/mozilla/fenix/session/PrivateNotificationService.kt b/app/src/main/java/org/mozilla/fenix/session/PrivateNotificationService.kt index 94f21a60a..2e0b47b03 100644 --- a/app/src/main/java/org/mozilla/fenix/session/PrivateNotificationService.kt +++ b/app/src/main/java/org/mozilla/fenix/session/PrivateNotificationService.kt @@ -16,6 +16,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.metrics +import java.util.Locale /** * Manages notifications for private tabs. @@ -33,9 +34,28 @@ class PrivateNotificationService : AbstractPrivateNotificationService() { override fun NotificationCompat.Builder.buildNotification() { setSmallIcon(R.drawable.ic_private_browsing) - setContentTitle(applicationContext.getString(R.string.app_name_private_4, getString(R.string.app_name))) - setContentText(applicationContext.getString(R.string.notification_pbm_delete_text_2)) - color = ContextCompat.getColor(this@PrivateNotificationService, R.color.pbm_notification_color) + setContentTitle( + applicationContext.getString( + R.string.app_name_private_4, + getString(R.string.app_name) + ) + ) + setContentText( + applicationContext.getString( + R.string.notification_pbm_delete_text_2 + ) + ) + color = ContextCompat.getColor( + this@PrivateNotificationService, + R.color.pbm_notification_color + ) + } + + /** + * Update the existing notification when the [Locale] has been changed. + */ + override fun notifyLocaleChanged() { + super.refreshNotification() } @SuppressLint("MissingSuperCall") diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/DefaultLocaleSettingsController.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/DefaultLocaleSettingsController.kt index 46f30d451..8b78c7592 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/DefaultLocaleSettingsController.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/DefaultLocaleSettingsController.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.settings.advanced import android.app.Activity import android.content.Context import mozilla.components.support.locale.LocaleManager +import mozilla.components.support.locale.LocaleUseCases import java.util.Locale interface LocaleSettingsController { @@ -17,7 +18,8 @@ interface LocaleSettingsController { class DefaultLocaleSettingsController( private val activity: Activity, - private val localeSettingsStore: LocaleSettingsStore + private val localeSettingsStore: LocaleSettingsStore, + private val localeUseCase: LocaleUseCases ) : LocaleSettingsController { override fun handleLocaleSelected(locale: Locale) { @@ -26,7 +28,7 @@ class DefaultLocaleSettingsController( return } localeSettingsStore.dispatch(LocaleSettingsAction.Select(locale)) - LocaleManager.setNewLocale(activity, locale.toLanguageTag()) + LocaleManager.setNewLocale(activity, localeUseCase, locale) LocaleManager.updateBaseConfiguration(activity, locale) activity.recreate() } @@ -36,7 +38,7 @@ class DefaultLocaleSettingsController( return } localeSettingsStore.dispatch(LocaleSettingsAction.Select(localeSettingsStore.state.localeList[0])) - LocaleManager.resetToSystemDefault(activity) + LocaleManager.resetToSystemDefault(activity, localeUseCase) LocaleManager.updateBaseConfiguration(activity, localeSettingsStore.state.localeList[0]) activity.recreate() } diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt index 4a307d29d..a2ee4533f 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt @@ -17,13 +17,15 @@ import kotlinx.android.synthetic.main.fragment_locale_settings.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.ktx.android.view.hideKeyboard +import mozilla.components.support.locale.LocaleUseCases import org.mozilla.fenix.R import org.mozilla.fenix.components.StoreProvider +import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.showToolbar class LocaleSettingsFragment : Fragment() { - private lateinit var store: LocaleSettingsStore + private lateinit var localeSettingsStore: LocaleSettingsStore private lateinit var interactor: LocaleSettingsInteractor private lateinit var localeView: LocaleSettingsView @@ -39,7 +41,10 @@ class LocaleSettingsFragment : Fragment() { ): View? { val view = inflater.inflate(R.layout.fragment_locale_settings, container, false) - store = StoreProvider.get(this) { + val browserStore = requireContext().components.core.store + val localeUseCase = LocaleUseCases(browserStore) + + localeSettingsStore = StoreProvider.get(this) { LocaleSettingsStore( createInitialLocaleSettingsState(requireContext()) ) @@ -47,7 +52,8 @@ class LocaleSettingsFragment : Fragment() { interactor = LocaleSettingsInteractor( controller = DefaultLocaleSettingsController( activity = requireActivity(), - localeSettingsStore = store + localeSettingsStore = localeSettingsStore, + localeUseCase = localeUseCase ) ) localeView = LocaleSettingsView(view.locale_container, interactor) @@ -87,7 +93,7 @@ class LocaleSettingsFragment : Fragment() { @ExperimentalCoroutinesApi override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - consumeFrom(store) { + consumeFrom(localeSettingsStore) { localeView.update(it) } } diff --git a/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt b/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt index c1f4f463d..d55b6f2ea 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/advanced/LocaleSettingsControllerTest.kt @@ -15,6 +15,7 @@ import io.mockk.spyk import io.mockk.verify import io.mockk.verifyAll import mozilla.components.support.locale.LocaleManager +import mozilla.components.support.locale.LocaleUseCases import org.junit.Before import org.junit.Test import java.util.Locale @@ -23,13 +24,20 @@ class LocaleSettingsControllerTest { private val activity = mockk(relaxed = true) private val localeSettingsStore: LocaleSettingsStore = mockk(relaxed = true) + private val localeUseCases: LocaleUseCases = mockk(relaxed = true) private val mockState = LocaleSettingsState(mockk(), mockk(), mockk()) private lateinit var controller: DefaultLocaleSettingsController @Before fun setup() { - controller = spyk(DefaultLocaleSettingsController(activity, localeSettingsStore)) + controller = spyk( + DefaultLocaleSettingsController( + activity, + localeSettingsStore, + localeUseCases + ) + ) mockkObject(LocaleManager) mockkStatic("org.mozilla.fenix.settings.advanced.LocaleManagerExtensionKt") @@ -45,11 +53,13 @@ class LocaleSettingsControllerTest { verifyAll(inverse = true) { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) - LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) + LocaleManager.setNewLocale(activity, locale = selectedLocale) activity.recreate() } with(controller) { - verify(inverse = true) { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } + verify(inverse = true) { + LocaleManager.updateBaseConfiguration(activity, selectedLocale) + } } } @@ -57,8 +67,9 @@ class LocaleSettingsControllerTest { fun `set a new locale from the list if other locale is chosen`() { val selectedLocale = Locale("en", "UK") val otherLocale: Locale = mockk() + every { localeUseCases.notifyLocaleChanged } returns mockk() every { localeSettingsStore.state } returns mockState.copy(selectedLocale = otherLocale) - every { LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) } returns activity + every { LocaleManager.setNewLocale(activity, localeUseCases, selectedLocale) } returns activity with(controller) { every { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } just Runs } @@ -66,7 +77,7 @@ class LocaleSettingsControllerTest { controller.handleLocaleSelected(selectedLocale) verify { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) } - verify { LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) } + verify { LocaleManager.setNewLocale(activity, localeUseCases, selectedLocale) } verify { activity.recreate() } with(controller) { verify { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } @@ -76,9 +87,11 @@ class LocaleSettingsControllerTest { @Test fun `set a new locale from the list if default locale is not selected`() { val selectedLocale = Locale("en", "UK") + every { localeUseCases.notifyLocaleChanged } returns mockk() every { localeSettingsStore.state } returns mockState.copy(selectedLocale = selectedLocale) every { LocaleManager.getCurrentLocale(activity) } returns null - every { LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) } returns activity + every { LocaleManager.setNewLocale(activity, localeUseCases, selectedLocale) } returns activity + with(controller) { every { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } just Runs } @@ -86,7 +99,7 @@ class LocaleSettingsControllerTest { controller.handleLocaleSelected(selectedLocale) verify { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) } - verify { LocaleManager.setNewLocale(activity, selectedLocale.toLanguageTag()) } + verify { LocaleManager.setNewLocale(activity, localeUseCases, selectedLocale) } verify { activity.recreate() } with(controller) { verify { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } @@ -103,7 +116,7 @@ class LocaleSettingsControllerTest { verifyAll(inverse = true) { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) - LocaleManager.resetToSystemDefault(activity) + LocaleManager.resetToSystemDefault(activity, localeUseCases) activity.recreate() with(controller) { LocaleManager.updateBaseConfiguration(activity, selectedLocale) @@ -114,8 +127,9 @@ class LocaleSettingsControllerTest { @Test fun `set the default locale as the new locale`() { val selectedLocale = Locale("en", "UK") + every { localeUseCases.notifyLocaleChanged } returns mockk() every { localeSettingsStore.state } returns mockState.copy(localeList = listOf(selectedLocale)) - every { LocaleManager.resetToSystemDefault(activity) } just Runs + every { LocaleManager.resetToSystemDefault(activity, localeUseCases) } just Runs with(controller) { every { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } just Runs } @@ -123,7 +137,7 @@ class LocaleSettingsControllerTest { controller.handleDefaultLocaleSelected() verify { localeSettingsStore.dispatch(LocaleSettingsAction.Select(selectedLocale)) } - verify { LocaleManager.resetToSystemDefault(activity) } + verify { LocaleManager.resetToSystemDefault(activity, localeUseCases) } verify { activity.recreate() } with(controller) { verify { LocaleManager.updateBaseConfiguration(activity, selectedLocale) } diff --git a/buildSrc/src/main/java/AndroidComponents.kt b/buildSrc/src/main/java/AndroidComponents.kt index 564238efa..6cf291a80 100644 --- a/buildSrc/src/main/java/AndroidComponents.kt +++ b/buildSrc/src/main/java/AndroidComponents.kt @@ -3,5 +3,5 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ object AndroidComponents { - const val VERSION = "74.0.20210322143147" + const val VERSION = "74.0.20210323143308" }