fix(browser): the pill's site-settings line only told the truth after you opened page info

`sitePermissions` was filled in exactly one place — inside `showPageInfo`, from
the answer the broker sends when the sheet is about to open. So a freshly
opened window said "Nothing allowed yet" about a site it had already been
granted the camera on, and only stopped saying it once you opened the sheet
that made it ask. Page info itself was always right; the summary above it was
not.

The registry lives in the main process and does not call back, so the window
has to ask. It now asks when the origin changes, which is when the answer can
differ, and keeps the last origin so a same-site navigation is not a round
trip per page.

An edit made in the sheet also folds straight into the summary. The registry
stays authoritative — this only stops the line behind the sheet disagreeing
with the sheet in front of it until the next navigation.

Found while testing "Open full screen": that window reported "Nothing allowed
yet" for brainstorm.world while its own page info showed Camera = Allow.
Verified on an SM-T220: the line now reads "Camera allowed" right after the
edit, and again in a brand-new window without opening page info at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vitor Pamplona
2026-09-26 22:41:40 -04:00
co-authored by Claude Opus 5
parent 28bf170f92
commit 3b019b45d0
@@ -155,6 +155,9 @@ class NappletBrowserActivity : ComponentActivity() {
// same address don't each trigger a round-trip.
private var lastFavoriteQueryUrl: String? = null
/** The origin whose site permissions the pill is already showing. */
private var lastSitePermissionOrigin: String? = null
// What Recents shows for this task: the page's title, favicon and theme colour.
private var pageTitle: String? = null
private var pageIcon: Bitmap? = null
@@ -771,6 +774,20 @@ class NappletBrowserActivity : ComponentActivity() {
copy(chrome = chrome.copy(url = url), title = if (newSite) BrowserChrome.displayHost(url) else title, isFavorite = false)
}
}
// The pill's "Site settings" line summarises this origin's camera/mic/location answers, and the
// registry that holds them lives in the main process. Until this was asked for on navigation, the
// only thing that ever filled it was opening page info — so a window said "Nothing allowed yet"
// about a site it had already been granted the camera on, and only stopped lying once you opened
// the sheet that made it ask.
BrowserChrome.originOf(url)?.let { origin ->
if (origin != lastSitePermissionOrigin) {
lastSitePermissionOrigin = origin
querySitePermissions(origin) { decisions ->
updateUi { copy(sitePermissions = decisions.filterValues { it != Decision.ASK }) }
}
}
}
if (url == lastFavoriteQueryUrl) return
lastFavoriteQueryUrl = url
val msg =
@@ -1383,6 +1400,14 @@ class NappletBrowserActivity : ComponentActivity() {
decision: Decision,
) {
BrowserChrome.originOf(currentUrl())?.let { rememberSitePermission(it, permission, decision) }
// Keep the pill's summary in step with the sheet the change was made in. The registry
// is authoritative and lives in the other process, but it does not call back, so an
// edit made here would otherwise not show up until the next navigation.
updateUi {
val next = sitePermissions.toMutableMap()
if (decision == Decision.ASK) next.remove(permission) else next[permission] = decision
copy(sitePermissions = next)
}
}
override fun onClearSiteData() {