Spec: System Bar (MVP)
Implementable contract for v0.1 System Bar. Overview narrative: system-bars.md. Scope freeze: mvp.md.
Purpose
Persistent wayfinding chrome: slotted entries with large targets, stable positions, and restriction-aware activation.
Anatomy
┌──────────────────────────────────────────────────────────┐
│ [leading slots…] [center slots…] [trailing…] │
└──────────────────────────────────────────────────────────┘
| Region | Typical entries |
|---|---|
| Leading | Home / map |
| Center | Optional OEM mark or HVAC/media peek |
| Trailing | App grid / notifications (gated) |
Slots are data-driven — OEMs configure without forking the widget (extension model).
States
| State | Behavior |
|---|---|
| Default | All configured slots visible per policy |
| Restricted / Moving | Complex entries Substitute or Block per restriction-states |
| Day / Night | Token schemes |
| Focused | Rotary/DPAD focus ring from tokens |
| Disabled item | Visible, non-activatable (when Substitute/Disable) |
Sizes & type (from tokens)
| Token (stub) | Role |
|---|---|
cabin.component.systemBar.height | Bar height |
cabin.component.systemBar.iconSize | Icons |
cabin.component.systemBar.itemMinSize | Touch minimum |
cabin.component.systemBar.gap | Inter-item gap |
cabin.type.role.label | Optional short labels |
cabin.color.scheme.*.container / onContainer | Bar chrome fill + content |
cabin.color.scheme.*.outline | Separators / unselected chrome |
cabin.color.scheme.*.surface / onSurface | Surrounding surface roles |
Stub file: tokens/cabin.tokens.json.
Day/night schemes also carry locked warning / error / charging for
adjacent Status chrome — see token-schema.
Compliance gates
| Interaction | Gating |
|---|---|
NavigateSimple | Allow in Moving/Restricted |
MediaTransport / HvacPeek | Allow (limited); no deep setup |
OpenComplexApp / OpenKeyboard / FilterOrSort | Block or Substitute while Moving/Restricted |
Safety class: Convenience chrome — do not bury safety-critical controls exclusively here.
Missing CabinComplianceHost is fail-closed (GateDisposition.Block)
for activating slot entries.
Planned Views API (MVP primary)
class CabinSystemBarView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : ViewGroup(context, attrs) {
fun setSlots(slots: CabinSystemBarSlots) { /* … */ }
fun setCompliance(host: CabinComplianceHost) { /* … */ }
}
Alpha implementation: dev.decoupled.cabin.views.CabinSystemBarView in
cabin-views / CabinViews.
Compose API (Experimental parity)
@Composable
fun CabinSystemBar(
slots: CabinSystemBarSlots,
modifier: Modifier = Modifier,
)
Experimental implementation: dev.decoupled.cabin.compose.CabinSystemBar in
cabin-compose / CabinCompose. Same Restriction Engine gates and token
roles as Views; wrap with CabinTheme. Not for SystemUI Soong adoption.
Acceptance criteria (MVP)
- Slot configuration without core fork
- Matrix behavior matches restriction-states for System Bar
- Touch minima from tokens
- Day/night via Theme Kit
- Content descriptions on icon-only entries
- No dependency on
cabin-compose
Related
- Status Bar spec
- Views
- Compose (Experimental parity)
- Build-tree