tor-browser

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

commit ecbfaf8159aec595013ce3edefb2be7af747a114
parent c4856b04fbfae7b54de746adf61629cb6f7f1564
Author: Marcin KoziƄski <mkozinski@mozilla.com>
Date:   Thu,  2 Oct 2025 13:03:27 +0000

Bug 1992079 - Keep legacy review prompt behavior if Nimbus flag for custom review prompt disabled r=android-reviewers,twhite

Differential Revision: https://phabricator.services.mozilla.com/D267197

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Components.kt | 2++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/reviewprompt/ReviewPromptMiddleware.kt | 37+++++++++++++++++++++++++++++++------
Amobile/android/fenix/app/src/test/java/org/mozilla/fenix/reviewprompt/LegacyReviewPromptTriggerTest.kt | 34++++++++++++++++++++++++++++++++++
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/reviewprompt/ReviewPromptMiddlewareTest.kt | 2++
4 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Components.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Components.kt @@ -290,6 +290,8 @@ class Components(private val context: Context) { SetupChecklistTelemetryMiddleware(), ReviewPromptMiddleware( isReviewPromptFeatureEnabled = { settings.customReviewPromptFeatureEnabled }, + numberOfAppLaunches = { settings.numberOfAppLaunches }, + isDefaultBrowser = { settings.isDefaultBrowser }, isTelemetryEnabled = { settings.isTelemetryEnabled }, createJexlHelper = nimbus::createJexlHelper, nimbusEventStore = nimbus.events, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/reviewprompt/ReviewPromptMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/reviewprompt/ReviewPromptMiddleware.kt @@ -26,6 +26,8 @@ private const val REVIEW_PROMPT_SHOWN_NIMBUS_EVENT_ID = "review_prompt_shown" * [Middleware] evaluating the triggers to show a review prompt. * * @param isReviewPromptFeatureEnabled If returns false disables the entire feature and prompt will never be shown. + * @param numberOfAppLaunches Returns number of app launches. + * @param isDefaultBrowser Returns true if app is set as the default system browser. * @param isTelemetryEnabled Returns true if the user allows sending technical and interaction telemetry. * @param createJexlHelper Returns a helper for evaluating JEXL expressions. * @param buildTriggerMainCriteria Builds a sequence of trigger's main criteria that all need to be true. @@ -35,21 +37,20 @@ private const val REVIEW_PROMPT_SHOWN_NIMBUS_EVENT_ID = "review_prompt_shown" */ class ReviewPromptMiddleware( private val isReviewPromptFeatureEnabled: () -> Boolean, + private val numberOfAppLaunches: () -> Int, + private val isDefaultBrowser: () -> Boolean, private val isTelemetryEnabled: () -> Boolean, private val createJexlHelper: () -> NimbusMessagingHelperInterface, private val buildTriggerMainCriteria: (NimbusMessagingHelperInterface) -> Sequence<Boolean> = - TiggerBuilder.mainCriteria(isReviewPromptFeatureEnabled), + TiggerBuilder::mainCriteria, private val buildTriggerSubCriteria: (NimbusMessagingHelperInterface) -> Sequence<Boolean> = TiggerBuilder::subCriteria, private val nimbusEventStore: NimbusEventStore, ) : Middleware<AppState, AppAction> { private object TiggerBuilder { - fun mainCriteria( - isReviewPromptEnabled: () -> Boolean, - ): (NimbusMessagingHelperInterface) -> Sequence<Boolean> = { jexlHelper -> - sequence { - yield(isReviewPromptEnabled()) + fun mainCriteria(jexlHelper: NimbusMessagingHelperInterface): Sequence<Boolean> { + return sequence { yield(hasNotBeenPromptedLastFourMonths(jexlHelper)) yield(usedAppOnAtLeastFourOfLastSevenDays(jexlHelper)) } @@ -90,6 +91,16 @@ class ReviewPromptMiddleware( return } + if (!isReviewPromptFeatureEnabled()) { + // Keep the simpler legacy behavior. + if (legacyReviewPromptTrigger(numberOfAppLaunches, isDefaultBrowser)) { + context.dispatch(ShowPlayStorePrompt) + } else { + context.dispatch(DoNotShowReviewPrompt) + } + return + } + createJexlHelper().use { jexlHelper -> val allMainCriteriaSatisfied = buildTriggerMainCriteria(jexlHelper).all { it } if (!allMainCriteriaSatisfied) { @@ -158,3 +169,17 @@ internal fun usedAppOnAtLeastFourOfLastSevenDays( ): Boolean { return jexlHelper.evalJexlSafe("'app_opened'|eventCountNonZero('Days', 7) >= 4") } + +private const val NUMBER_OF_LAUNCHES_REQUIRED = 5 + +/** + * Matches logic from ReviewPromptController.shouldShowPrompt, which has been deleted. + * Kept so we can fall back to it in case the custom review prompt is disabled with a kill-switch. + */ +@VisibleForTesting +internal fun legacyReviewPromptTrigger( + numberOfAppLaunches: () -> Int, + isDefaultBrowser: () -> Boolean, +): Boolean { + return isDefaultBrowser() && numberOfAppLaunches() >= NUMBER_OF_LAUNCHES_REQUIRED +} diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/reviewprompt/LegacyReviewPromptTriggerTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/reviewprompt/LegacyReviewPromptTriggerTest.kt @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.reviewprompt + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class LegacyReviewPromptTriggerTest { + + private var numberOfAppLaunches = 5 + private var isDefaultBrowser = true + + @Test + fun `WHEN app is the default browser AND was launched at least 5 times THEN legacy trigger is satisfied`() { + assertTrue(legacyReviewPromptTrigger({ numberOfAppLaunches }, { isDefaultBrowser })) + } + + @Test + fun `WHEN app isn't the default browser THEN legacy trigger is not satisfied`() { + isDefaultBrowser = false + + assertFalse(legacyReviewPromptTrigger({ numberOfAppLaunches }, { isDefaultBrowser })) + } + + @Test + fun `WHEN app was launched less than 5 times THEN legacy trigger is not satisfied`() { + numberOfAppLaunches = 4 + + assertFalse(legacyReviewPromptTrigger({ numberOfAppLaunches }, { isDefaultBrowser })) + } +} diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/reviewprompt/ReviewPromptMiddlewareTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/reviewprompt/ReviewPromptMiddlewareTest.kt @@ -29,6 +29,8 @@ class ReviewPromptMiddlewareTest { middlewares = listOf( ReviewPromptMiddleware( isReviewPromptFeatureEnabled = { true }, + numberOfAppLaunches = { 5 }, + isDefaultBrowser = { true }, isTelemetryEnabled = { isTelemetryEnabled }, createJexlHelper = { object : NimbusMessagingHelperInterface {