Skip to main content

Spec: Status Bar (MVP)

Implementable contract for v0.1 Status Bar. Overview narrative: status-bars.md. Scope freeze: mvp.md.

Purpose

Glanceable vehicle/system status: connectivity, clock, battery/SOC, alerts. Honest unavailable/stale/fault presentation. Deep links gated by Restriction Engine.

Anatomy

┌──────────────────────────────────────────────────────────┐
│ 🕒 📶 🔋 80% 72°F ⚠ (alerts) │
└──────────────────────────────────────────────────────────┘

Items are an ordered list; overflow policy is program-defined but must not drop active fault affordances.

States

StateBehavior
NormalItems show live values
Warning / fault presentSemantic warning/error tokens; persistent until cleared
ChargingCharging accent recognizable
Signal unavailable / staleExplicit degraded UI — never fake “off”
RestrictedSettings deep links Block/Substitute per matrix
Day / NightToken schemes

Live warning / charging accents are selected via CabinStatusEmphasis on CabinStatusGlyph. Signal unavailable / stale / fault always override emphasis. Missing CabinComplianceHost is fail-closed (GateDisposition.Block) for activating deep links.

Sizes & type (from tokens)

Token (stub)Role
cabin.component.statusBar.heightBar height
cabin.component.statusBar.iconSizeIcons
cabin.component.statusBar.itemGapGap
cabin.type.role.statusStatus typography
cabin.color.scheme.*.warning / error / chargingFeedback / domain (night contrast locked)
cabin.color.scheme.*.container / onContainer / outlineBar chrome

Stub file: tokens/cabin.tokens.json. See token-schema for day/night role table.

Compliance gates

InteractionGating
Glance displayAlways
StatusDeepLink informationalSubstitute while Moving/Restricted
StatusDeepLink settings/setupBlock while Moving/Restricted
OpenKeyboardBlock outside Parked

Safety class: mostly Informational; fault presentation is safety-adjacent (safety-critical).

Planned Views API (MVP primary)

class CabinStatusBarView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : ViewGroup(context, attrs) {
fun setItems(items: List<CabinStatusItem>) { /* … */ }
fun setCompliance(host: CabinComplianceHost) { /* … */ }
}

Alpha implementation: dev.decoupled.cabin.views.CabinStatusBarView in cabin-views / CabinViews. Signal lives in cabin-compliance.

Compose API (Experimental parity)

@Composable
fun CabinStatusBar(
items: List<CabinStatusItem>,
modifier: Modifier = Modifier,
)

Experimental implementation: dev.decoupled.cabin.compose.CabinStatusBar in cabin-compose / CabinCompose. Same Signal / emphasis / deep-link gating as Views; wrap with CabinTheme. Not for SystemUI Soong adoption.

Acceptance criteria (MVP)

  • Exhaustive unavailable/stale/fault rendering for signal-backed items
  • Matrix behavior matches restriction-states for Status Bar
  • Fault/warning contrast day/night
  • Content descriptions present
  • No dependency on cabin-compose