From affd8204e5d41c808228791f7868a0109df84a7c Mon Sep 17 00:00:00 2001 From: "oana.horvath" Date: Thu, 29 Feb 2024 15:42:08 +0200 Subject: [PATCH] Bug 1882777 - Request permission to reset locale in UI tests --- .../fenix/helpers/AppAndSystemHelper.kt | 86 +++++++++---------- .../org/mozilla/fenix/helpers/TestSetup.kt | 40 ++++++--- 2 files changed, 67 insertions(+), 59 deletions(-) diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/AppAndSystemHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/AppAndSystemHelper.kt index 534930f59..8bd8467f2 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/AppAndSystemHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/AppAndSystemHelper.kt @@ -356,64 +356,60 @@ object AppAndSystemHelper { /** * Changes the default language of the entire device, not just the app. - * Runs on Debug variant as we don't want to adjust Release permission manifests * Runs the test in its testBlock. * Cleans up and sets the default locale after it's done. - * As a safety measure, always add the resetSystemLocaleToEnUS() method in the tearDown method of your Class. */ fun runWithSystemLocaleChanged(locale: Locale, testRule: ActivityTestRule, testBlock: () -> Unit) { + val defaultLocale = Locale.getDefault() + + try { + setSystemLocale(locale) + testBlock() + ThreadUtils.runOnUiThread { testRule.activity.recreate() } + } catch (e: Exception) { + e.printStackTrace() + } finally { + setSystemLocale(defaultLocale) + } + } + + /** + * Changes the default language of the entire device, not just the app. + * We can only use this if we're running on a debug build, otherwise it will change the permission manifests in release builds. + */ + fun setSystemLocale(locale: Locale) { if (Config.channel.isDebug) { /* Sets permission to change device language */ + Log.i( + TAG, + "setSystemLocale: Requesting permission to change system locale to $locale.", + ) PermissionRequester().apply { addPermissions( Manifest.permission.CHANGE_CONFIGURATION, ) requestPermissions() } - - val defaultLocale = Locale.getDefault() - - try { - setSystemLocale(locale) - testBlock() - ThreadUtils.runOnUiThread { testRule.activity.recreate() } - } catch (e: Exception) { - e.printStackTrace() - } finally { - setSystemLocale(defaultLocale) - } - } - } - - /** - * Resets the default language of the entire device back to EN-US. - * In case of a test instrumentation crash, the finally statement in the - * runWithSystemLocaleChanged(locale: Locale) method, will not be reached. - * Add this method inside the tearDown method of your test class, where the above method is used. - * Note: If set inside the ActivityTestRule's afterActivityFinished() method, this also won't work, - * as the methods inside it are not always executed: https://github.com/android/android-test/issues/498 - */ - fun resetSystemLocaleToEnUS() { - if (Locale.getDefault() != Locale.US) { - Log.i(TAG, "Resetting system locale to EN US") - setSystemLocale(Locale.US) + Log.i( + TAG, + "setSystemLocale: Received permission to change system locale to $locale.", + ) + val activityManagerNative = Class.forName("android.app.ActivityManagerNative") + val am = activityManagerNative.getMethod("getDefault", *arrayOfNulls(0)) + .invoke(activityManagerNative, *arrayOfNulls(0)) + val config = + InstrumentationRegistry.getInstrumentation().context.resources.configuration + config.javaClass.getDeclaredField("locale")[config] = locale + config.javaClass.getDeclaredField("userSetLocale").setBoolean(config, true) + am.javaClass.getMethod( + "updateConfiguration", + Configuration::class.java, + ).invoke(am, config) } - } - - /** - * Changes the default language of the entire device, not just the app. - */ - fun setSystemLocale(locale: Locale) { - val activityManagerNative = Class.forName("android.app.ActivityManagerNative") - val am = activityManagerNative.getMethod("getDefault", *arrayOfNulls(0)) - .invoke(activityManagerNative, *arrayOfNulls(0)) - val config = InstrumentationRegistry.getInstrumentation().context.resources.configuration - config.javaClass.getDeclaredField("locale")[config] = locale - config.javaClass.getDeclaredField("userSetLocale").setBoolean(config, true) - am.javaClass.getMethod( - "updateConfiguration", - Configuration::class.java, - ).invoke(am, config) + Log.i( + TAG, + "setSystemLocale: Changed system locale to $locale.", + ) } fun putAppToBackground() { diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestSetup.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestSetup.kt index 3413dc84c..292350825 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestSetup.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestSetup.kt @@ -11,8 +11,8 @@ import org.junit.After import org.junit.Before import org.mozilla.fenix.ext.components import org.mozilla.fenix.helpers.Constants.TAG -import org.mozilla.fenix.helpers.TestHelper.appContext import org.mozilla.fenix.ui.robots.notificationShade +import java.util.Locale /** * Standard Test setup and tear down methods to run before each test. @@ -26,19 +26,12 @@ open class TestSetup { @Before open fun setUp() { Log.i(TAG, "TestSetup: Starting the @Before setup") - // Initializing this as part of class construction, below the rule would throw a NPE. - // So we are initializing this here instead of in all related tests. - Log.i(TAG, "TestSetup: Trying to initialize the browserStore instance") - browserStore = appContext.components.core.store - Log.i(TAG, "TestSetup: Initialized the browserStore instance") - // Clear pre-existing notifications. - notificationShade { - cancelAllShownNotifications() - } - runBlocking { // Reset locale to EN-US if needed. - AppAndSystemHelper.resetSystemLocaleToEnUS() + // Because of https://bugzilla.mozilla.org/show_bug.cgi?id=1812183, some items might not be updated. + if (Locale.getDefault() != Locale.US) { + AppAndSystemHelper.setSystemLocale(Locale.US) + } // Check and clear the downloads folder, in case the tearDown method is not executed. // This will only work in case of a RetryTestRule execution. AppAndSystemHelper.clearDownloadsFolder() @@ -52,6 +45,16 @@ open class TestSetup { AppAndSystemHelper.deletePermissionsStorage() } + // Initializing this as part of class construction, below the rule would throw a NPE. + // So we are initializing this here instead of in all related tests. + Log.i(TAG, "TestSetup: Trying to initialize the browserStore instance") + browserStore = TestHelper.appContext.components.core.store + Log.i(TAG, "TestSetup: Initialized the browserStore instance") + // Clear pre-existing notifications. + notificationShade { + cancelAllShownNotifications() + } + mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() } @@ -68,7 +71,16 @@ open class TestSetup { @After open fun tearDown() { Log.i(TAG, "TestSetup: Starting the @After tearDown methods.") - // Check and clear the downloads folder. - AppAndSystemHelper.clearDownloadsFolder() + runBlocking { + // Check and clear the downloads folder. + AppAndSystemHelper.clearDownloadsFolder() + + // Reset locale to EN-US if needed. + // This method is only here temporarily, to set the language before a new activity is started. + // TODO: When https://bugzilla.mozilla.org/show_bug.cgi?id=1812183 is fixed, it should be removed. + if (Locale.getDefault() != Locale.US) { + AppAndSystemHelper.setSystemLocale(Locale.US) + } + } } }