Skip to content

fix: gate rumble/motion on the active path, not the model DB - #146

Merged
emir-hasanbegovic merged 1 commit into
mainfrom
fix/standard-path-rumble-capability
Jul 22, 2026
Merged

fix: gate rumble/motion on the active path, not the model DB#146
emir-hasanbegovic merged 1 commit into
mainfrom
fix/standard-path-rumble-capability

Conversation

@emir-hasanbegovic

@emir-hasanbegovic emir-hasanbegovic commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Problem

A Switch Pro over USB advertised rumble on Standard and Bluetooth (and left the input inspector's rumble test buttons enabled), but only Direct actually rumbled.

Root causes

1. The capability layer ORed two path-specific signals. CapabilityComposer.deviceControllerLayer and ConfigureBindingsViewModel computed rumble as device.hasRumble || native.modelHasRumble(...). The framework probe is authoritative for Standard/Bluetooth; the model DB (parserHasRumble) only for Direct. ORing let the Direct-only capability leak onto the framework paths.

2. The framework probe is itself a false positive for the Switch protocol. vibratorManager.vibratorIds is non-empty for a Switch Pro — Android registers a vibrator — but it can't drive Nintendo's proprietary HD-rumble, which only our Direct path speaks. So even after fixing (1), device.hasRumble stayed true and the framework paths still advertised rumble that never fires.

Fix

  • Per-path resolution (mirrors MainViewModel's existing split): a Direct synthetic reads the parser DB, a framework pad reads the OS probe. CapabilityComposer is the single source of truth; the bindings VM reads it, and the inspector disables its rumble buttons when the path can't rumble.
  • Suppress the false-positive probe at its source (probeRumble) for models the native DB maps to the SWITCH_PRO_USB parser — the Pro, Joy-Con Charging Grip, and Online controllers, plus any future Switch-protocol device — via a new modelFrameworkRumbleUnreliable lookup (mirrors modelHasRumble). device.hasRumble is now truthful for every downstream surface (PathCard, composer, bindings, wizard, inspector); Direct still works through the model DB.
  • Re-probe the vibrator in onInputDeviceChanged, symmetric with the existing late-gyro re-probe.

Net: rumble shows only where it fires — Direct for Switch-protocol pads; framework for Xbox/PlayStation where the OS actually drives it.

Why the parser, not the Nintendo vendor

Keying on SWITCH_PRO_USB (the native model DB's parser field) targets the exact cause — the proprietary protocol — and covers the whole family without a hand-maintained VID:PID list that could drift from the DB.

Tests

  • usb_parsers_test.cpp: parserFrameworkRumbleUnreliable true for SWITCH_PRO_USB, false for the Xbox/PlayStation families.
  • CapabilityComposerTest: per-path matrix (framework trusts the probe / ignores the model DB; synthetic reads the model DB; end-to-end capabilityForCandidate for a Standard Switch Pro).

Local CI — all green

clang-format · check_play_metadata · ktlintCheck · detekt · lint · testDebugUnitTest · nativeTest (168/168) · assembleDebug. Emulator instrumented job runs in CI (no local device attached).

🤖 Generated with Claude Code

@emir-hasanbegovic
emir-hasanbegovic force-pushed the fix/standard-path-rumble-capability branch 4 times, most recently from ab270d3 to 894a1a1 Compare July 21, 2026 22:59
A Switch Pro over USB advertised rumble on Standard and Bluetooth (and left the
input inspector's test buttons live) but only Direct actually rumbled. Two causes:

1. The capability layer ORed the framework actuator/sensor probe with the native
   model DB, so Direct-only capability leaked onto the framework paths. Resolve
   motion/rumble per path instead, mirroring MainViewModel's split: a Direct
   synthetic reads the parser DB, a framework pad reads the OS probe.
   CapabilityComposer is the single source of truth; the bindings VM reads it and
   the inspector disables and dims its rumble buttons when the path can't rumble.

2. The OS probe is itself a false positive for the Switch protocol: Android
   registers a framework vibrator it can't drive (Nintendo's proprietary HD-rumble,
   which only our Direct path speaks). Suppress the probe at its source for models
   the native DB maps to the SWITCH_PRO_USB parser (Pro, Joy-Con Grip, Online pads),
   so no framework path advertises dead rumble; Direct still works via the model DB.

Also re-probe the vibrator in onInputDeviceChanged, symmetric with the existing
late-gyro re-probe.
@emir-hasanbegovic
emir-hasanbegovic force-pushed the fix/standard-path-rumble-capability branch from 894a1a1 to 5844713 Compare July 21, 2026 23:41
@emir-hasanbegovic
emir-hasanbegovic merged commit 77225bd into main Jul 22, 2026
9 checks passed
@emir-hasanbegovic
emir-hasanbegovic deleted the fix/standard-path-rumble-capability branch July 22, 2026 00:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants