Skip to main content

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…] │
└──────────────────────────────────────────────────────────┘
RegionTypical entries
LeadingHome / map
CenterOptional OEM mark or HVAC/media peek
TrailingApp grid / notifications (gated)

Slots are data-driven — OEMs configure without forking the widget (extension model).

States

StateBehavior
DefaultAll configured slots visible per policy
Restricted / MovingComplex entries Substitute or Block per restriction-states
Day / NightToken schemes
FocusedRotary/DPAD focus ring from tokens
Disabled itemVisible, non-activatable (when Substitute/Disable)

Sizes & type (from tokens)

Token (stub)Role
cabin.component.systemBar.heightBar height
cabin.component.systemBar.iconSizeIcons
cabin.component.systemBar.itemMinSizeTouch minimum
cabin.component.systemBar.gapInter-item gap
cabin.type.role.labelOptional short labels
cabin.color.scheme.*.container / onContainerBar chrome fill + content
cabin.color.scheme.*.outlineSeparators / unselected chrome
cabin.color.scheme.*.surface / onSurfaceSurrounding 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

InteractionGating
NavigateSimpleAllow in Moving/Restricted
MediaTransport / HvacPeekAllow (limited); no deep setup
OpenComplexApp / OpenKeyboard / FilterOrSortBlock 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