Symptom
Any orientation change loses the page. The tab does not merely reload — it resets to the home state with an empty address bar.
Reproduction (x86_64 emulator, v0.4.0)
Verified on a neutral page so this isn't site-specific:
- Load
https://example.com/.
- In WebView DevTools:
window.__m = 'alive' (document.title → Example Domain).
- Rotate:
adb shell settings put system user_rotation 1.
- Re-evaluate:
String(window.__m) → undefined, document.title → "", location.href → about:blank.
On screen afterwards: the Freedom home screen, empty address bar, page gone.
Cause
Two things compound:
app/src/main/AndroidManifest.xml declares no android:configChanges on .MainActivity, so Android destroys and recreates the Activity on rotation (and on other config changes — locale, uiMode, keyboard).
- Tab state (
TabsState / BrowserState) is held in plain Compose remember, with no ViewModel or rememberSaveable, so recreation starts from a fresh home tab. The WebView instances go with it.
Impact
Affects every site, not just content-addressed ones: scroll position, form input, video playback position, SPA state, and any in-page session are lost whenever the user turns the phone. It also interacts badly with pages that request landscape themselves (see #9): a successful screen.orientation.lock('landscape') would trigger this same teardown, so fullscreen support must not land before this is fixed.
Found while investigating why an ENS-hosted WebGL game (mythosgame.eth, which calls screen.orientation.lock("landscape") when a run starts) returned users to a menu on mobile.
Fix sketch
- Add
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|keyboardHidden|uiMode" to .MainActivity so rotation no longer recreates it. Compose handles the config change fine; the WebViews survive.
- Independently, make tab state survive process death / genuine recreation — hoist it into a
ViewModel, and persist the per-tab URL list so a cold restore reopens the same tabs. WebView.saveState/restoreState can carry per-tab history.
(1) alone fixes the reported symptom; (2) is the durable version and also covers low-memory kills.
Acceptance
- Rotating with a page open keeps the page, its scroll position, and its JS state (the
window.__m marker above survives).
- Rotating with several tabs open preserves the tab set and the active tab.
Symptom
Any orientation change loses the page. The tab does not merely reload — it resets to the home state with an empty address bar.
Reproduction (x86_64 emulator, v0.4.0)
Verified on a neutral page so this isn't site-specific:
https://example.com/.window.__m = 'alive'(document.title→Example Domain).adb shell settings put system user_rotation 1.String(window.__m)→undefined,document.title→"",location.href→about:blank.On screen afterwards: the Freedom home screen, empty address bar, page gone.
Cause
Two things compound:
app/src/main/AndroidManifest.xmldeclares noandroid:configChangeson.MainActivity, so Android destroys and recreates the Activity on rotation (and on other config changes — locale, uiMode, keyboard).TabsState/BrowserState) is held in plain Composeremember, with noViewModelorrememberSaveable, so recreation starts from a fresh home tab. The WebView instances go with it.Impact
Affects every site, not just content-addressed ones: scroll position, form input, video playback position, SPA state, and any in-page session are lost whenever the user turns the phone. It also interacts badly with pages that request landscape themselves (see #9): a successful
screen.orientation.lock('landscape')would trigger this same teardown, so fullscreen support must not land before this is fixed.Found while investigating why an ENS-hosted WebGL game (
mythosgame.eth, which callsscreen.orientation.lock("landscape")when a run starts) returned users to a menu on mobile.Fix sketch
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|keyboardHidden|uiMode"to.MainActivityso rotation no longer recreates it. Compose handles the config change fine; the WebViews survive.ViewModel, and persist the per-tab URL list so a cold restore reopens the same tabs.WebView.saveState/restoreStatecan carry per-tab history.(1) alone fixes the reported symptom; (2) is the durable version and also covers low-memory kills.
Acceptance
window.__mmarker above survives).