Skip to content

Commit 2908a38

Browse files
authored
Fire Mode: Add BrowserMode with plumbing (#8478)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1207418217763355/task/1214579513091724?focus=true ### Description This PR adds the new `BrowserMode` and the related interfaces and their concrete implementations: - `BrowserModeStateHolder` that exposes enum class `BrowserMode { REGULAR, FIRE }`, which is the single source of truth for current mode. Theming overlay, tab switcher VM, mode-toggle pill, sync entry points, repository providers — all observe this Flow. - Adds `FireModeAvailability` that checks the feature flag and the WebView feature support - Adds `BrowserMode` plumbing to the main entry points Related API proposal: https://app.asana.com/1/137249556945/project/1207418217763355/task/1214579944546013?focus=true ### Steps to test this PR Smoke testing that the app is launched correctly and opening an external link works as expected is sufficient. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches core `BrowserActivity` intent processing and tab creation, adding mode-based recreation and deferred-intent handling which could affect external link/widget/shortcut launches. New mode plumbing is guarded by availability checks but has broad surface area across entry points. > > **Overview** > Introduces a new cross-module `BrowserMode` concept (`REGULAR`/`FIRE`) with a `BrowserModeStateHolder` source-of-truth and an app implementation (`RealBrowserModeStateHolder`). > > Updates `BrowserActivity` and tab creation to be mode-aware (adapter/`BrowserTabFragment` arguments, DuckChat fragment args), and recreates the activity on mode changes; external entry-point intents can now be stamped as `LAUNCH_REQUIRES_REGULAR_MODE` and, if received while in `FIRE`, are deferred across a FIRE→REGULAR switch before processing. > > Adds a new `fire-mode-api`/`fire-mode-impl` with `FireModeAvailability` (feature flag + WebView MultiProfile capability), wires it into `BrowserViewModel.switchToMode`, and updates numerous launch points (widgets, shortcuts, onboarding/settings/internal screens, tests) to pass a `BrowserLaunchSource` and correctly stamp intents. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2f0669e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 74936c7 commit 2908a38

45 files changed

Lines changed: 823 additions & 40 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ dependencies {
420420
implementation project(':fingerprint-protection-impl')
421421
implementation project(':fingerprint-protection-store')
422422

423+
implementation project(':fire-mode-api')
423424
implementation project(':fire-mode-impl')
424425

425426
implementation project(':element-hiding-impl')

app/src/androidTest/java/com/duckduckgo/espresso/RequestBlocklistTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import androidx.test.ext.junit.rules.activityScenarioRule
3030
import androidx.test.platform.app.InstrumentationRegistry
3131
import com.duckduckgo.app.browser.BrowserActivity
3232
import com.duckduckgo.app.browser.R
33+
import com.duckduckgo.app.browser.mode.InAppNavigation
3334
import com.duckduckgo.espresso.privacy.preparationsForPrivacyTest
3435
import com.duckduckgo.privacy.config.impl.network.JSONObjectAdapter
3536
import com.squareup.moshi.JsonAdapter
@@ -45,6 +46,7 @@ class RequestBlocklistTest {
4546
var activityScenarioRule = activityScenarioRule<BrowserActivity>(
4647
BrowserActivity.intent(
4748
InstrumentationRegistry.getInstrumentation().targetContext,
49+
launchSource = InAppNavigation,
4850
queryExtra = "https://privacy-test-pages.site/privacy-protections",
4951
),
5052
)

app/src/androidTest/java/com/duckduckgo/espresso/privacy/CookiesTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import androidx.test.ext.junit.rules.activityScenarioRule
3030
import androidx.test.platform.app.InstrumentationRegistry
3131
import com.duckduckgo.app.browser.BrowserActivity
3232
import com.duckduckgo.app.browser.R
33+
import com.duckduckgo.app.browser.mode.InAppNavigation
3334
import com.duckduckgo.espresso.PrivacyTest
3435
import com.duckduckgo.espresso.WebViewIdlingResource
3536
import com.duckduckgo.privacy.config.impl.network.JSONObjectAdapter
@@ -46,6 +47,7 @@ class CookiesTest {
4647
var activityScenarioRule = activityScenarioRule<BrowserActivity>(
4748
BrowserActivity.intent(
4849
InstrumentationRegistry.getInstrumentation().targetContext,
50+
launchSource = InAppNavigation,
4951
queryExtra = "https://privacy-test-pages.site/privacy-protections/storage-blocking/?store",
5052
),
5153
)

app/src/androidTest/java/com/duckduckgo/espresso/privacy/FingerprintProtectionTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.test.ext.junit.rules.activityScenarioRule
3434
import androidx.test.platform.app.InstrumentationRegistry
3535
import com.duckduckgo.app.browser.BrowserActivity
3636
import com.duckduckgo.app.browser.R
37+
import com.duckduckgo.app.browser.mode.InAppNavigation
3738
import com.duckduckgo.espresso.JsObjectIdlingResource
3839
import com.duckduckgo.espresso.PrivacyTest
3940
import com.duckduckgo.espresso.WebViewIdlingResource
@@ -53,6 +54,7 @@ class FingerprintProtectionTest {
5354
var activityScenarioRule = activityScenarioRule<BrowserActivity>(
5455
BrowserActivity.intent(
5556
InstrumentationRegistry.getInstrumentation().targetContext,
57+
launchSource = InAppNavigation,
5658
"https://privacy-test-pages.site/privacy-protections",
5759
),
5860
)

app/src/androidTest/java/com/duckduckgo/espresso/privacy/GpcTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.test.ext.junit.rules.activityScenarioRule
3434
import androidx.test.platform.app.InstrumentationRegistry
3535
import com.duckduckgo.app.browser.BrowserActivity
3636
import com.duckduckgo.app.browser.R
37+
import com.duckduckgo.app.browser.mode.InAppNavigation
3738
import com.duckduckgo.espresso.JsObjectIdlingResource
3839
import com.duckduckgo.espresso.PrivacyTest
3940
import com.duckduckgo.espresso.WebViewIdlingResource
@@ -52,6 +53,7 @@ class GpcTest {
5253
var activityScenarioRule = activityScenarioRule<BrowserActivity>(
5354
BrowserActivity.intent(
5455
InstrumentationRegistry.getInstrumentation().targetContext,
56+
launchSource = InAppNavigation,
5557
queryExtra = "https://privacy-test-pages.site/privacy-protections",
5658
),
5759
)

app/src/androidTest/java/com/duckduckgo/espresso/privacy/HttpsUpgradesTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import androidx.test.ext.junit.rules.activityScenarioRule
3131
import androidx.test.platform.app.InstrumentationRegistry
3232
import com.duckduckgo.app.browser.BrowserActivity
3333
import com.duckduckgo.app.browser.R
34+
import com.duckduckgo.app.browser.mode.InAppNavigation
3435
import com.duckduckgo.common.utils.isHttps
3536
import com.duckduckgo.espresso.PrivacyTest
3637
import com.duckduckgo.espresso.WebViewIdlingResource
@@ -48,6 +49,7 @@ class HttpsUpgradesTest {
4849
var activityScenarioRule = activityScenarioRule<BrowserActivity>(
4950
BrowserActivity.intent(
5051
InstrumentationRegistry.getInstrumentation().targetContext,
52+
launchSource = InAppNavigation,
5153
queryExtra = "http://privacy-test-pages.site/privacy-protections/https-upgrades/",
5254
),
5355
)

app/src/androidTest/java/com/duckduckgo/espresso/privacy/RequestBlockingTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import androidx.test.platform.app.InstrumentationRegistry
3030
import com.duckduckgo.app.browser.BrowserActivity
3131
import com.duckduckgo.app.browser.R
3232
import com.duckduckgo.app.browser.clickMenuItem
33+
import com.duckduckgo.app.browser.mode.InAppNavigation
3334
import com.duckduckgo.espresso.*
3435
import com.duckduckgo.privacy.config.impl.network.JSONObjectAdapter
3536
import com.squareup.moshi.JsonAdapter
@@ -47,6 +48,7 @@ class RequestBlockingTest {
4748
var activityScenarioRule = activityScenarioRule<BrowserActivity>(
4849
BrowserActivity.intent(
4950
InstrumentationRegistry.getInstrumentation().targetContext,
51+
launchSource = InAppNavigation,
5052
queryExtra = "https://privacy-test-pages.site/privacy-protections/request-blocking/?run",
5153
),
5254
)

app/src/androidTest/java/com/duckduckgo/espresso/privacy/SurrogatesTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import androidx.test.platform.app.InstrumentationRegistry
2828
import com.duckduckgo.app.browser.BrowserActivity
2929
import com.duckduckgo.app.browser.R
3030
import com.duckduckgo.app.browser.clickMenuItem
31+
import com.duckduckgo.app.browser.mode.InAppNavigation
3132
import com.duckduckgo.espresso.*
3233
import com.duckduckgo.privacy.config.impl.network.JSONObjectAdapter
3334
import com.squareup.moshi.JsonAdapter
@@ -45,6 +46,7 @@ class SurrogatesTest {
4546
var activityScenarioRule = activityScenarioRule<BrowserActivity>(
4647
BrowserActivity.intent(
4748
InstrumentationRegistry.getInstrumentation().targetContext,
49+
launchSource = InAppNavigation,
4850
queryExtra = "https://privacy-test-pages.site/privacy-protections/surrogates/",
4951
),
5052
)

app/src/internal/java/com/duckduckgo/app/audit/AuditSettingsActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import com.duckduckgo.app.audit.AuditSettingsViewModel.Companion.STEP_3
3838
import com.duckduckgo.app.audit.AuditSettingsViewModel.Companion.SURROGATES
3939
import com.duckduckgo.app.browser.BrowserActivity
4040
import com.duckduckgo.app.browser.databinding.ActivityAuditSettingsBinding
41+
import com.duckduckgo.app.browser.mode.InAppNavigation
4142
import com.duckduckgo.common.ui.DuckDuckGoActivity
4243
import com.duckduckgo.common.ui.viewbinding.viewBinding
4344
import com.duckduckgo.di.scopes.ActivityScope
@@ -97,7 +98,7 @@ class AuditSettingsActivity : DuckDuckGoActivity() {
9798
}
9899

99100
private fun goToUrl(url: String) {
100-
startActivity(BrowserActivity.intent(this, url))
101+
startActivity(BrowserActivity.intent(this, launchSource = InAppNavigation, queryExtra = url))
101102
finish()
102103
}
103104

app/src/internal/java/com/duckduckgo/app/dev/settings/DevSettingsActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import com.duckduckgo.app.browser.BrowserActivity
3232
import com.duckduckgo.app.browser.R
3333
import com.duckduckgo.app.browser.R.layout
3434
import com.duckduckgo.app.browser.databinding.ActivityDevSettingsBinding
35+
import com.duckduckgo.app.browser.mode.InAppNavigation
3536
import com.duckduckgo.app.browser.webview.WebContentDebuggingFeature
3637
import com.duckduckgo.app.dev.settings.DevSettingsViewModel.Command
3738
import com.duckduckgo.app.dev.settings.DevSettingsViewModel.Command.ChangePrivacyConfigUrl
@@ -139,7 +140,7 @@ class DevSettingsActivity : DuckDuckGoActivity() {
139140
}
140141

141142
private fun goToUrl(url: String) {
142-
startActivity(BrowserActivity.intent(this, url))
143+
startActivity(BrowserActivity.intent(this, launchSource = InAppNavigation, queryExtra = url))
143144
finish()
144145
}
145146

0 commit comments

Comments
 (0)