Skip to content

Fire Mode: Escape hatch#8917

Open
0nko wants to merge 10 commits into
feature/ondrej/fire-mode-dialogfrom
feature/ondrej/fire-mode-escape-hatch
Open

Fire Mode: Escape hatch#8917
0nko wants to merge 10 commits into
feature/ondrej/fire-mode-dialogfrom
feature/ondrej/fire-mode-escape-hatch

Conversation

@0nko

@0nko 0nko commented Jun 18, 2026

Copy link
Copy Markdown
Member

Task/Issue URL: https://app.asana.com/1/137249556945/project/72649045549333/task/1215736845374133?focus=true

Description

This PR adds the Fire mode support to escape hatch.

Steps to test this PR

Prerequisites

  • Internal build with androidBrowserConfig.showNTPAfterIdleReturn enabled (feature-flag inventory).
  • Settings → General → After inactivity → Choose an inactivity interval → Always (immediate), and set what you see to New Tab Page.
  • fireMode.fireTabs enabled for scenarios 1–5; disabled for scenario 6.
  • Cold-start note: a quick swipe-and-reopen often keeps the process alive (a warm start). For a true cold start, force-stop the app (App info → Force stop, or adb shell am force-stop com.duckduckgo.mobile.android.debug) before relaunching.

1. Cold start — last tab was a Regular tab

  • Open a Regular tab on a real site (e.g. example.com); background it.
  • Cold start the app.
  • Expect: opens in Regular mode on the NTP with a "Return to… <site>" hatch; tapping it returns to that tab.

2. Cold start — last tab was a Fire tab

  • Enter Fire mode, open a Fire tab on a site / Duck.ai chat.
  • Cold start the app.
  • Expect: opens in Regular mode; the hatch shows "Last used Fire Tab" with the fire placeholder icon, and never the Fire tab's real title/URL/favicon (privacy).
  • Tap the hatch → switches into Fire mode and opens that exact Fire tab — not a new/blank Fire tab.

2b. Cold start — Fire tab, returned from the search / input screen

  • Repeat scenario 2's setup (cold start with the last-used tab being a Fire tab).
  • On the Regular-mode NTP, tap the address bar / search to open the input screen — the same "Last used Fire Tab" hatch appears there.
  • Tap it → switches into Fire mode and opens that exact Fire tab (not a new/blank Fire tab).

3. Hot start in Fire mode

  • In Fire mode, background the app, then reopen (warm — don't kill the process).
  • Expect: a new Fire tab opens, with no escape hatch.

4. Hot start in Regular mode

  • In Regular mode, background the app, then reopen.
  • Expect: existing behavior — the hatch returns to the last Regular tab.

5. Fire-target hatch controls

  • On the Fire-target hatch (scenario 2), overflow ⋮ → Close Tab removes the Fire tab; Undo restores it. (Known: the 🔥 burn button is a no-op for Fire tabs for now, pending cross-mode single-tab clearing.)

6. fireTabs OFF reverts cleanly

  • Disable the flag in the internal feature-flag inventory (dev settings → Feature flags → fireMode → turn off fireTabs), then fully restart the app (Fire-mode availability is cached per process).
  • Repeat scenario 2's setup.
  • Expect: the hatch behaves like the previous Regular-only escape hatch — no "Last used Fire Tab"; only Regular tabs are offered.

Note

Medium Risk
Changes core browser launch, mode-switch recreate, and tab routing across Regular/Fire; Fire-target privacy depends on not surfacing Fire tab metadata in Regular UI.

Overview
Adds Fire mode to the after-idle escape hatch on the Regular-mode NTP (and input screen). A new EscapeHatchTargetResolver picks the return target from the most recently accessed tab in Regular and/or Fire (when Fire tabs are enabled); Fire targets use a generic “Last used Fire Tab” label and placeholder icon so real title/URL/favicon never appear in Normal UI.

Tapping the hatch (or returning from the input screen) uses openExistingTabInMode and a new PendingAction.OpenExistingTab so the activity can switch mode and recreate before selecting the tab. ModeSwitchRecreateSignal marks programmatic mode-switch recreates so FirstScreenHandler does not re-run launch/inactivity logic and overwrite the pending action. ShowOnAppLaunchOptionHandler is updated to respect current mode (e.g. NTP-on-idle in Fire without the Regular-only hatch path; Specific/Last-opened skipped in Fire).

Hatch close/undo/commit routes tab operations to the correct mode’s TabRepository; tests cover bundle round-trips, resolver behavior, and Fire hatch view model cases.

Reviewed by Cursor Bugbot for commit 3f6348a. Bugbot is set up for automated code reviews on this repo. Configure here.

0nko commented Jun 18, 2026

Copy link
Copy Markdown
Member Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f5eb9c6. Configure here.

Comment thread app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt
@0nko 0nko requested a review from CDRussell June 18, 2026 20:27
@0nko 0nko changed the title Fire mode: Escape hatch Fire Mode: Escape hatch Jun 22, 2026

@CDRussell CDRussell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved because it's working as described and correctly. Think you're missing an API proposal though?

Comment on lines 138 to +149
if (state.shouldShow) {
binding.returnHatchSiteTitle.text = state.titleOrPlaceholder()
if (state.isDuckChat) {
binding.returnHatchFavicon.setImageResource(CommonR.drawable.ic_duckai)
if (state.mode == BrowserMode.FIRE) {
binding.returnHatchSiteTitle.text = context.getString(R.string.newTabReturnHatchFireTabTitle)
binding.returnHatchFavicon.setImageResource(CommonR.drawable.ic_fire_tab_placeholder_96)
} else {
faviconJob += viewModel.viewModelScope.launch {
faviconManager.loadToViewFromLocalWithRetry(state.tabId, state.url, binding.returnHatchFavicon)
binding.returnHatchSiteTitle.text = state.titleOrPlaceholder()
if (state.isDuckChat) {
binding.returnHatchFavicon.setImageResource(CommonR.drawable.ic_duckai)
} else {
faviconJob += viewModel.viewModelScope.launch {
faviconManager.loadToViewFromLocalWithRetry(state.tabId, state.url, binding.returnHatchFavicon)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: if we add a third mode in future, this the kind of code that might become a quiet footgun. Rather than if (fire) else { }, if you made it a when it'll become a compile-time problem to ensure we solve correctly if we add any additional modes.

* The hatch only ever renders in Regular mode, so an [EscapeHatchTarget] with [EscapeHatchTarget.mode]
* == [BrowserMode.FIRE] also implies that tapping the hatch must switch into Fire mode to open it.
*/
interface EscapeHatchTargetResolver {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a corresponding API proposal for this?

@0nko 0nko force-pushed the feature/ondrej/fire-mode-escape-hatch branch from c31d734 to c8c653e Compare June 22, 2026 19:31
@0nko 0nko force-pushed the feature/ondrej/fire-mode-dialog branch from 65ada87 to 8053a49 Compare June 22, 2026 19:31
0nko and others added 10 commits June 22, 2026 23:31
…s-mode tab opening

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…get tab mode

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o the right tab database

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ns to its target tab

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-dialog branch from 84c7c36 to 44bd718 Compare June 22, 2026 21:31
@0nko 0nko force-pushed the feature/ondrej/fire-mode-escape-hatch branch from c8c653e to 3f6348a Compare June 22, 2026 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants