tor-browser

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

commit 91542930a6fad0c783d94d8012f1d91deef5b879
parent 152ea86547a898ab8bf3226a3e5beb8365ccadc9
Author: Chloe Zhou <chloezhouny@gmail.com>
Date:   Wed, 31 Dec 2025 00:51:02 +0000

Bug 2005375 - Make aboutwelcome auto_advance time configurable r=omc-reviewers,ai-frontend-reviewers,sachung,Mardak

Add support for configurable auto_advance timing in aboutwelcome screens.
The auto_advance property now accepts both the string format and
a new object format with actionEl and actionTimeMS properties.

The new object format allows specifying custom timing and the string format continues to work with 20-second default.

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

Diffstat:
Mbrowser/app/profile/firefox.js | 1+
Mbrowser/components/aboutwelcome/content-src/components/MultiStageProtonScreen.jsx | 9+++++++--
Mbrowser/components/aboutwelcome/content/aboutwelcome.bundle.js | 7+++++--
Mbrowser/components/aboutwelcome/tests/unit/MultiStageAboutWelcome.test.jsx | 45+++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/aiwindow/ui/content/firstrun.js | 8+++++++-
Mbrowser/components/aiwindow/ui/test/browser/browser_aiwindow_firstrun.js | 7+++++--
6 files changed, 70 insertions(+), 7 deletions(-)

diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js @@ -2255,6 +2255,7 @@ pref("browser.aiwindow.enabled", false); pref("browser.aiwindow.endpoint", "https://mlpa-prod-prod-mozilla.global.ssl.fastly.net/v1"); pref("browser.aiwindow.insights", false); pref("browser.aiwindow.insightsLogLevel", "Warn"); +pref("browser.aiwindow.firstrun.autoAdvanceMS", 3000); pref("browser.aiwindow.firstrun.modelChoice", ""); pref("browser.aiwindow.model", ""); diff --git a/browser/components/aboutwelcome/content-src/components/MultiStageProtonScreen.jsx b/browser/components/aboutwelcome/content-src/components/MultiStageProtonScreen.jsx @@ -19,18 +19,23 @@ import { LinkParagraph } from "./LinkParagraph"; import { ContentTiles } from "./ContentTiles"; import { InstallButton } from "./InstallButton"; +const DEFAULT_AUTO_ADVANCE_MS = 20000; + export const MultiStageProtonScreen = props => { const { autoAdvance, handleAction, order } = props; useEffect(() => { if (autoAdvance) { + const value = autoAdvance?.actionEl ?? autoAdvance; + const timeout = autoAdvance?.actionTimeMS ?? DEFAULT_AUTO_ADVANCE_MS; + const timer = setTimeout(() => { handleAction({ currentTarget: { - value: autoAdvance, + value, }, name: "AUTO_ADVANCE", }); - }, 20000); + }, timeout); return () => clearTimeout(timer); } return () => {}; diff --git a/browser/components/aboutwelcome/content/aboutwelcome.bundle.js b/browser/components/aboutwelcome/content/aboutwelcome.bundle.js @@ -1080,6 +1080,7 @@ __webpack_require__.r(__webpack_exports__); +const DEFAULT_AUTO_ADVANCE_MS = 20000; const MultiStageProtonScreen = props => { const { autoAdvance, @@ -1088,14 +1089,16 @@ const MultiStageProtonScreen = props => { } = props; (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => { if (autoAdvance) { + const value = autoAdvance?.actionEl ?? autoAdvance; + const timeout = autoAdvance?.actionTimeMS ?? DEFAULT_AUTO_ADVANCE_MS; const timer = setTimeout(() => { handleAction({ currentTarget: { - value: autoAdvance + value }, name: "AUTO_ADVANCE" }); - }, 20000); + }, timeout); return () => clearTimeout(timer); } return () => {}; diff --git a/browser/components/aboutwelcome/tests/unit/MultiStageAboutWelcome.test.jsx b/browser/components/aboutwelcome/tests/unit/MultiStageAboutWelcome.test.jsx @@ -169,6 +169,51 @@ describe("MultiStageAboutWelcome module", () => { telemetryStub.restore(); }); + it("should autoAdvance with configurable time and send appropriate telemetry", () => { + let clock = sinon.useFakeTimers(); + const screens = [ + { + auto_advance: { + actionEl: "primary_button", + actionTimeMS: 5000, + }, + content: { + title: "test title", + subtitle: "test subtitle", + primary_button: { + label: "Test Button", + action: { + navigate: true, + }, + }, + }, + }, + ]; + const AUTO_ADVANCE_PROPS = { + defaultScreens: screens, + metricsFlowUri: "http://localhost/", + message_id: "DEFAULT_ABOUTWELCOME", + utm_term: "default", + startScreen: 0, + }; + const wrapper = mount(<MultiStageAboutWelcome {...AUTO_ADVANCE_PROPS} />); + wrapper.update(); + const finishStub = sandbox.stub(global, "AWFinish"); + const telemetryStub = sinon.stub( + AboutWelcomeUtils, + "sendActionTelemetry" + ); + + assert.notCalled(finishStub); + clock.tick(5001); + assert.calledOnce(finishStub); + assert.calledOnce(telemetryStub); + assert.equal(telemetryStub.lastCall.args[2], "AUTO_ADVANCE"); + clock.restore(); + finishStub.restore(); + telemetryStub.restore(); + }); + it("should send telemetry ping on collectSelect", () => { const screens = [ { diff --git a/browser/components/aiwindow/ui/content/firstrun.js b/browser/components/aiwindow/ui/content/firstrun.js @@ -11,8 +11,11 @@ ChromeUtils.defineESModuleGetters(lazy, { "moz-src:///browser/components/aiwindow/ui/modules/AIWindow.sys.mjs", }); const MODEL_PREF = "browser.aiwindow.firstrun.modelChoice"; +const AUTO_ADVANCE_PREF = "browser.aiwindow.firstrun.autoAdvanceMS"; const BRAND_DARK_PURPLE = "#210340"; +const autoAdvanceMS = Services.prefs.getIntPref(AUTO_ADVANCE_PREF); + const AI_WINDOW_CONFIG = { id: "AI_WINDOW_WELCOME", template: "spotlight", @@ -22,7 +25,10 @@ const AI_WINDOW_CONFIG = { screens: [ { id: "AI_WINDOW_INTRO", - auto_advance: "primary_button", + auto_advance: { + actionEl: "primary_button", + actionTimeMS: autoAdvanceMS, + }, force_hide_steps_indicator: true, content: { fullscreen: true, diff --git a/browser/components/aiwindow/ui/test/browser/browser_aiwindow_firstrun.js b/browser/components/aiwindow/ui/test/browser/browser_aiwindow_firstrun.js @@ -14,6 +14,10 @@ async function openFirstrunPage() { } add_task(async function test_firstrun_welcome_screen_renders() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.aiwindow.firstrun.autoAdvanceMS", 0]], + }); + const tab = await openFirstrunPage(); await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { @@ -32,8 +36,7 @@ add_task(async function test_firstrun_welcome_screen_renders() { await ContentTaskUtils.waitForCondition( () => content.document.querySelector(".screen.AI_WINDOW_CHOOSE_MODEL"), - "Wait for the AI Window choose model screen to be rendered", - 25000 + "Wait for the AI Window choose model screen to be rendered" ); });