docs/developer/foldable-device-support.md
This document describes the foldable device support implementation for Thunderbird Android. The feature automatically switches between single-pane and split-view layouts based on the device's fold state.
Foldable devices like Samsung Galaxy Fold and Google Pixel Fold offer different screen sizes depending on their posture:
Thunderbird already supports split-screen views, but these are static (Always/Never) or orientation-based (When in Landscape). Users of foldable devices must manually change the setting when switching between folded and unfolded states.
File: core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/GeneralSettings.kt
Added new option:
enum class SplitViewMode {
ALWAYS,
NEVER,
WHEN_IN_LANDSCAPE,
WHEN_UNFOLDED, // New
}
File: legacy/ui/legacy/src/main/java/com/fsck/k9/ui/foldable/FoldableStateObserver.kt
Responsibilities:
WindowInfoTracker from Jetpack WindowManagerWindowLayoutInfo into simplified FoldableStateStateFlow<FoldableState> for lifecycle-aware collectionFoldableState Enum:
enum class FoldableState {
FOLDED, // Device is folded (small screen)
UNFOLDED, // Device is unfolded (large screen)
UNKNOWN, // Not a foldable or state unknown
}
State Detection:
FoldingFeature.State.FLAT → UNFOLDEDFoldingFeature.State.HALF_OPENED → UNFOLDED (laptop mode)FoldingFeature → UNKNOWNFile: legacy/ui/legacy/src/main/java/com/fsck/k9/activity/MainActivity.kt
Changes:
FoldableStateObserver via KoinuseSplitView() with WHEN_UNFOLDED logicrecreate() on fold/unfold eventsFoldableStateObserver detects UNFOLDEDhandleFoldableStateChange() is calledFOLDEDWindowInfoTracker (Android System)
↓
WindowLayoutInfo with FoldingFeature
↓
FoldableStateObserver.processWindowLayoutInfo()
↓ (Debounce 300ms)
FoldableState (FOLDED/UNFOLDED/UNKNOWN)
↓
StateFlow emission
↓
MainActivity.handleFoldableStateChange()
↓
recreate() if layout switch needed
↓
onCreate() → useSplitView() checks currentState
↓
Correct layout loaded
gradle/libs.versions.toml:
[versions]
androidxWindow = "1.3.0"
[libraries]
androidx-window = { module = "androidx.window:window", version.ref = "androidxWindow" }
legacy/ui/legacy/build.gradle.kts:
implementation(libs.androidx.window)
recreate() is only called once (Android standard behavior)UNFOLDEDUNKNOWNFoldingFeature.bounds not usedFile: core/ui/compose/common/src/test/kotlin/app/k9mail/core/ui/compose/common/window/FoldableStateObserverTest.kt
Tests:
Emulator: Foldable device (e.g., "7.6" Fold-in with outer display")
Test scenarios:
recreate():
WindowSizeClass integration