tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 78ec6e6ec805789616028d1c1208b9eb878d68cb
parent b58542e3069392018190ee4f7c74b2908f3ae696
Author: Serban Stanca <sstanca@mozilla.com>
Date:   Wed,  8 Oct 2025 14:54:17 +0300

Revert "Bug 1987602 - For app link startups, don't refresh top sites until visual completeness is ready r=android-reviewers,boek" for causing fenix-debug failures.

This reverts commit 5850b768d44e145e3bf715727f3c8631543c7b6a.

This reverts commit f058acff613df88148f40f499a3788431fd390d4.

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt | 5+----
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/TopSitesRefresher.kt | 34+++++-----------------------------
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/perf/StartupPathProvider.kt | 57+++++++++++++--------------------------------------------
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/home/TopSitesRefresherTest.kt | 103++-----------------------------------------------------------------------------
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/perf/StartupPathProviderTest.kt | 6+++---
5 files changed, 24 insertions(+), 181 deletions(-)

diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -145,7 +145,6 @@ import org.mozilla.fenix.nimbus.FxNimbus import org.mozilla.fenix.onboarding.ReEngagementNotificationWorker import org.mozilla.fenix.pbmlock.DefaultPrivateBrowsingLockStorage import org.mozilla.fenix.pbmlock.PrivateBrowsingLockFeature -import org.mozilla.fenix.perf.DefaultStartupPathProvider import org.mozilla.fenix.perf.MarkersActivityLifecycleCallbacks import org.mozilla.fenix.perf.MarkersFragmentLifecycleCallbacks import org.mozilla.fenix.perf.Performance @@ -309,7 +308,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { // Tracker for contextual menu (Copy|Search|Select all|etc...) private var actionMode: ActionMode? = null - private val startupPathProvider: StartupPathProvider = DefaultStartupPathProvider() + private val startupPathProvider = StartupPathProvider() private lateinit var startupTypeTelemetry: StartupTypeTelemetry private val onBackPressedCallback = object : UserInteractionOnBackPressedCallback( @@ -554,8 +553,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { TopSitesRefresher( settings = settings(), topSitesProvider = components.core.marsTopSitesProvider, - startupPathProvider = startupPathProvider, - visualCompletenessQueue = components.performance.visualCompletenessQueue, ), downloadSnackbar, privateBrowsingLockFeature, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/TopSitesRefresher.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/TopSitesRefresher.kt @@ -13,8 +13,6 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import mozilla.components.feature.top.sites.TopSitesProvider import mozilla.components.support.base.log.logger.Logger -import mozilla.components.support.utils.RunWhenReadyQueue -import org.mozilla.fenix.perf.StartupPathProvider import org.mozilla.fenix.utils.Settings /** @@ -22,17 +20,12 @@ import org.mozilla.fenix.utils.Settings * * @param settings Fenix [Settings] * @param topSitesProvider [TopSitesProvider] to refresh top sites - * @param visualCompletenessQueue [RunWhenReadyQueue] for visual completeness - * @param startupPathProvider [StartupPathProvider] that tells us whether the app was started - * for "app link" (aka [StartupPathProvider.StartupPath.VIEW]) or "home" (aka [StartupPathProvider.StartupPath.MAIN]) * @param dispatcher [CoroutineDispatcher] to use launch the refresh job. * Default value is [Dispatchers.IO]. It is helpful to improve testability */ class TopSitesRefresher( private val settings: Settings, private val topSitesProvider: TopSitesProvider, - private val visualCompletenessQueue: RunWhenReadyQueue, - private val startupPathProvider: StartupPathProvider, private val dispatcher: CoroutineDispatcher = Dispatchers.IO, ) : DefaultLifecycleObserver { @@ -40,35 +33,18 @@ class TopSitesRefresher( private val scope = CoroutineScope(dispatcher) override fun onResume(owner: LifecycleOwner) { - if (!settings.showContileFeature) return - - if (isAppLinkStartup()) { - // for app link startups - // do not refresh top sites until visual completeness is ready - // see bug https://bugzilla.mozilla.org/show_bug.cgi?id=1987602 - visualCompletenessQueue.runIfReadyOrQueue { - refreshTopSites() - } - } else { - refreshTopSites() - } - } - - override fun onPause(owner: LifecycleOwner) { - scope.cancel() - } - - private fun refreshTopSites() { scope.launch(dispatcher) { runCatching { - topSitesProvider.refreshTopSitesIfCacheExpired() + if (settings.showContileFeature) { + topSitesProvider.refreshTopSitesIfCacheExpired() + } }.onFailure { exception -> logger.error("Failed to refresh contile top sites", exception) } } } - private fun isAppLinkStartup(): Boolean { - return startupPathProvider.startupPathForActivity == StartupPathProvider.StartupPath.VIEW + override fun onPause(owner: LifecycleOwner) { + scope.cancel() } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/perf/StartupPathProvider.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/perf/StartupPathProvider.kt @@ -17,8 +17,11 @@ import androidx.lifecycle.LifecycleOwner * The "path" that this activity started in. See the * [Fenix perf glossary](https://wiki.mozilla.org/index.php?title=Performance/Fenix/Glossary) * for specific definitions. + * + * This should be a member variable of [Activity] because its data is tied to the lifecycle of an + * Activity. Call [attachOnActivityOnCreate] & [onIntentReceived] for this class to work correctly. */ -interface StartupPathProvider { +class StartupPathProvider { /** * The path the application took to @@ -26,14 +29,7 @@ interface StartupPathProvider { * for specific definitions. */ enum class StartupPath { - /** - * The startup path for the Main app - */ MAIN, - - /** - * The startup path if the user opens a link in the app - */ VIEW, /** @@ -50,42 +46,15 @@ interface StartupPathProvider { } /** - * The determined StartupPath for the given activity - */ - val startupPathForActivity: StartupPath - - /** - * Function to attach the startup path provider to a lifecycle/activity - */ - fun attachOnActivityOnCreate(lifecycle: Lifecycle, intent: Intent?) - - /** - * Function to invoke when a new intent has been received by the activity - */ - fun onIntentReceived(intent: Intent?) -} - -/** - * The "path" that this activity started in. See the - * [Fenix perf glossary](https://wiki.mozilla.org/index.php?title=Performance/Fenix/Glossary) - * for specific definitions. - * - * This should be a member variable of [Activity] because its data is tied to the lifecycle of an - * Activity. Call [attachOnActivityOnCreate] & [onIntentReceived] for this class to work correctly. - */ -internal class DefaultStartupPathProvider : StartupPathProvider { - - /** * Returns the [StartupPath] for the currently started activity. This value will be set * after an [Intent] is received that causes this activity to move into the STARTED state. */ - private var _startupPathForActivity = StartupPathProvider.StartupPath.NOT_SET - override val startupPathForActivity: StartupPathProvider.StartupPath - get() = _startupPathForActivity + var startupPathForActivity = StartupPath.NOT_SET + private set private var wasResumedSinceStartedState = false - override fun attachOnActivityOnCreate(lifecycle: Lifecycle, intent: Intent?) { + fun attachOnActivityOnCreate(lifecycle: Lifecycle, intent: Intent?) { lifecycle.addObserver(StartupPathLifecycleObserver()) onIntentReceived(intent) } @@ -97,17 +66,17 @@ internal class DefaultStartupPathProvider : StartupPathProvider { // URL, it'll perform a MAIN action. However, it's fairly representative of what users *intended* // to do when opening the app and shouldn't change much because it's based on Android system-wide // conventions, so it's probably fine for our purposes. - private fun getStartupPathFromIntent(intent: Intent): StartupPathProvider.StartupPath = when (intent.action) { - Intent.ACTION_MAIN -> StartupPathProvider.StartupPath.MAIN - Intent.ACTION_VIEW -> StartupPathProvider.StartupPath.VIEW - else -> StartupPathProvider.StartupPath.UNKNOWN + private fun getStartupPathFromIntent(intent: Intent): StartupPath = when (intent.action) { + Intent.ACTION_MAIN -> StartupPath.MAIN + Intent.ACTION_VIEW -> StartupPath.VIEW + else -> StartupPath.UNKNOWN } /** * Expected to be called when a new [Intent] is received by the [Activity]: i.e. * [Activity.onCreate] and [Activity.onNewIntent]. */ - override fun onIntentReceived(intent: Intent?) { + fun onIntentReceived(intent: Intent?) { // We want to set a path only if the intent causes the Activity to move into the STARTED state. // This means we want to discard any intents that are received when the app is foregrounded. // However, we can't use the Lifecycle.currentState to determine this because: @@ -116,7 +85,7 @@ internal class DefaultStartupPathProvider : StartupPathProvider { // - onIntentReceived can be called from the CREATED or STARTED state so we can't say == CREATED // So we're forced to track this state ourselves. if (!wasResumedSinceStartedState && intent != null) { - _startupPathForActivity = getStartupPathFromIntent(intent) + startupPathForActivity = getStartupPathFromIntent(intent) } } diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/home/TopSitesRefresherTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/home/TopSitesRefresherTest.kt @@ -4,8 +4,6 @@ package org.mozilla.fenix.home -import android.content.Intent -import androidx.lifecycle.Lifecycle import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -15,15 +13,11 @@ import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import mozilla.components.feature.top.sites.TopSite import mozilla.components.feature.top.sites.TopSitesProvider -import mozilla.components.support.test.rule.MainCoroutineRule -import mozilla.components.support.utils.RunWhenReadyQueue import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before -import org.junit.Rule import org.junit.Test import org.mozilla.fenix.helpers.lifecycle.TestLifecycleOwner -import org.mozilla.fenix.perf.StartupPathProvider import org.mozilla.fenix.utils.Settings /** @@ -31,20 +25,12 @@ import org.mozilla.fenix.utils.Settings */ class TopSitesRefresherTest { - private val testScheduler = TestCoroutineScheduler() - val testDispatcher = StandardTestDispatcher(testScheduler) - - @get:Rule - val coroutinesRule = MainCoroutineRule(testDispatcher = testDispatcher) - private val lifecycleOwner = TestLifecycleOwner() private val topSitesProvider = FakeTopSitesProvider() private val settings: Settings = mockk(relaxed = true) - private val visualCompletenessQueue = RunWhenReadyQueue() - private val startupPathProvider = - FakeStartupPathProvider(expectedPath = StartupPathProvider.StartupPath.NOT_SET) + private val testScheduler = TestCoroutineScheduler() private lateinit var topSitesRefresher: TopSitesRefresher @Before @@ -52,9 +38,7 @@ class TopSitesRefresherTest { topSitesRefresher = TopSitesRefresher( settings = settings, topSitesProvider = topSitesProvider, - visualCompletenessQueue = visualCompletenessQueue, - startupPathProvider = startupPathProvider, - dispatcher = testDispatcher, + dispatcher = StandardTestDispatcher(testScheduler), ) lifecycleOwner.registerObserver( @@ -86,79 +70,6 @@ class TopSitesRefresherTest { assertFalse(topSitesProvider.cacheRefreshed) } - @Test - fun `GIVEN app link startup WHEN lifecycle resumes AND visual completeness is ready THEN top sites are refreshed`() = - runTest(context = testScheduler) { - // given we want to show top sites - every { settings.showContileFeature } returns true - - // given that this is an app link startup - startupPathProvider.expectedPath = StartupPathProvider.StartupPath.VIEW - - // given that the visual completeness queue is read - visualCompletenessQueue.ready() - - // When we resume - lifecycleOwner.onResume() - advanceUntilIdle() - - // Then validate that cache is refreshed - assertTrue( - "App link startup with visual completeness should refresh cache", - topSitesProvider.cacheRefreshed, - ) - } - - @Test - fun `GIVEN app link startup WHEN lifecycle resumes AND visual completeness is NOT ready THEN top sites are NOT refreshed`() = - runTest(context = testScheduler) { - // given we want to show top sites - every { settings.showContileFeature } returns true - - // given that this is an app link startup - startupPathProvider.expectedPath = StartupPathProvider.StartupPath.VIEW - - // When we resume - lifecycleOwner.onResume() - advanceUntilIdle() - - // Then validate that cache is not refreshed - assertFalse( - "App link startup should not refresh cache before visual completeness", - topSitesProvider.cacheRefreshed, - ) - } - - @Test - fun `GIVEN app link startup WHEN lifecycle resumes THEN top sites are NOT refreshed only after visual completeness is ready`() = - runTest(context = testScheduler) { - // given we want to show top sites - every { settings.showContileFeature } returns true - - // given that this is an app link startup - startupPathProvider.expectedPath = StartupPathProvider.StartupPath.VIEW - - // When we resume - lifecycleOwner.onResume() - advanceUntilIdle() - - // Then validate that cache is not refreshed - assertFalse( - "App link startup should not refresh cache BEFORE visual completeness", - topSitesProvider.cacheRefreshed, - ) - - // When visual completeness queue is ready - visualCompletenessQueue.ready() - advanceUntilIdle() - - // Then cache should be refreshed - assertTrue( - "App link startup should refresh cache AFTER visual completeness", - topSitesProvider.cacheRefreshed, - ) - } - private class FakeTopSitesProvider : TopSitesProvider { var expectedTopSites: List<TopSite> = emptyList() @@ -170,14 +81,4 @@ class TopSitesRefresherTest { cacheRefreshed = true } } - - private class FakeStartupPathProvider( - var expectedPath: StartupPathProvider.StartupPath, - ) : StartupPathProvider { - override val startupPathForActivity: StartupPathProvider.StartupPath - get() = expectedPath - - override fun attachOnActivityOnCreate(lifecycle: Lifecycle, intent: Intent?) = Unit - override fun onIntentReceived(intent: Intent?) = Unit - } } diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/perf/StartupPathProviderTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/perf/StartupPathProviderTest.kt @@ -19,8 +19,8 @@ import org.mozilla.fenix.perf.StartupPathProvider.StartupPath class StartupPathProviderTest { - private lateinit var provider: DefaultStartupPathProvider - private lateinit var callbacks: DefaultStartupPathProvider.StartupPathLifecycleObserver + private lateinit var provider: StartupPathProvider + private lateinit var callbacks: StartupPathProvider.StartupPathLifecycleObserver @MockK private lateinit var intent: Intent @@ -28,7 +28,7 @@ class StartupPathProviderTest { fun setUp() { MockKAnnotations.init(this) - provider = DefaultStartupPathProvider() + provider = StartupPathProvider() callbacks = provider.getTestCallbacks() }