ImeWindow & Window Constraints
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowController.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeRootView.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowConstraints.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindow.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowSpec.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowProps.kt
- app/src/main/kotlin/dev/patrickgold/florisboard/FlorisImeService.kt
The ImeWindow & Window Constraints system manages the spatial representation, positioning, and resizing logic of the Input Method Editor (IME) within the Android environment. It ensures that the keyboard UI adapts correctly to various screen sizes, orientations, and form factors while maintaining interactivity and visibility constraints.
This system is built around a controller-based architecture that separates raw inset data, user preferences, and physical constraints from the high-level UI specifications used by Compose-based views.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowController.kt:29-37, app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindow.kt:76-88
Architectural Overview
The window management system utilizes a reactive data flow powered by Kotlin Coroutines and StateFlows. It bridges the gap between the InputMethodService and the Jetpack Compose UI.
Component Hierarchy
- ImeRootView: The top-level
AbstractComposeViewthat acts as the entry point for the IME UI. It hosts theImeWindowControllerand forces a Left-to-Right (LTR) layout for consistent positioning logic. - ImeWindowController: The central coordinator responsible for computing window specifications (
ImeWindowSpec) based on root insets and configurations. - ImeWindow: The primary UI container for keyboard components, which adjusts its size and offset according to the active window mode (Fixed or Floating).
- ImeWindowConstraints: A strict hierarchy of sizing limits (min/max/default) that prevents the window from becoming non-interactive or invisible.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeRootView.kt:42-53, app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowController.kt:40-45, app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindow.kt:133-145, app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowConstraints.kt:25-39
Window Data Flow
The following diagram illustrates how raw screen data is transformed into the final visual window specification:
This flow ensures that any change in screen size or user configuration immediately triggers a re-computation of the window's physical boundaries.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowController.kt:85-115, app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindow.kt:105-112
Window Constraints and Specifications
Constraints define the "safe zones" for the keyboard, while specifications represent the actual state of the window at any given moment.
Constraint Logic
ImeWindowConstraints are calculated lazily based on the device's ImeFormFactor. The system defines specific baseline screens for different devices (e.g., Phone Portrait, Tablet Landscape) to derive appropriate scaling factors.
| Property | Description |
|---|---|
baselineRowCount | The standard number of rows (default is 4.0) used for height calculations. |
minKeyboardHeight | The minimum height permitted to ensure the keyboard remains usable. |
maxKeyboardHeight | The maximum height permitted before the keyboard obstructs too much of the screen. |
dockToFixedHeight | The threshold at which a floating window "snaps" back to a fixed bottom position. |
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowConstraints.kt:53-73, app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowConstraints.kt:124-142
Window Modes
The system supports two primary operational modes, handled via sealed classes in ImeWindowSpec:
- Fixed Mode: Docked to the bottom of the screen. Supports "Normal," "Compact" (one-handed), and "Thumbs" (split) layouts.
- Floating Mode: Can be freely moved and resized across the root window area.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowSpec.kt:113-118, app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowSpec.kt:208-213
Window Config Editor
The Editor inner class within ImeWindowController manages the state for real-time move and resize gestures.
Editor States
Gestures modify the temporary ImeWindowSpec, which is then validated against ImeWindowConstraints before being persisted to the user's preferences.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowController.kt:472-500, app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowController.kt:587-598
Resizing Logic
Resizing is handled by resizedBy(offset, handle, ...) in the window specifications. It accounts for which "handle" (Top, Bottom, Left, Right) is being dragged to adjust keyboardHeight, keyboardWidth, padding, or offsets appropriately.
// Example: Resizing a Fixed window from the top
if (handle.top) {
keyboardHeight = (keyboardHeight - offset.y)
.coerceAtLeast(constraints.minKeyboardHeight.toEffective(rowCount, smartbarRowCount))
.coerceAtMost(constraints.maxKeyboardHeight - paddingBottom)
}
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowSpec.kt:174-180
Integration with InputMethodService
The FlorisImeService communicates with the ImeWindowController primarily through the onComputeInsets callback. This is critical for telling Android which parts of the screen are covered by the keyboard and which parts are touchable.
| Inset Type | Logic for Fixed Mode | Logic for Floating Mode |
|---|---|---|
contentTopInsets | Equal to the window's top boundary. | Equal to the root's bottom (no app resizing). |
visibleTopInsets | Equal to the window's top boundary. | Equal to the root's bottom (no app resizing). |
touchableRegion | Rectangle of the keyboard window. | Rectangle of the keyboard window. |
The system uses TOUCHABLE_INSETS_REGION exclusively to avoid a platform bug where touch input is occasionally not propagated to the root window.
Sources: app/src/main/kotlin/dev/patrickgold/florisboard/ime/window/ImeWindowController.kt:145-177, app/src/main/kotlin/dev/patrickgold/florisboard/FlorisImeService.kt:511-515
Conclusion
The ImeWindow system provides a robust framework for managing complex keyboard layouts. By using a constraint-based approach and a centralized controller, it ensures that the UI remains interactive and visually consistent across the diverse Android device ecosystem, whether in a standard docked position or a user-customized floating state.