forked from unom/punktfunk
Reported from the field: an SC2 wired or on its Puck dongle changes the console UI to the controller layout, but the same pad paired over Bluetooth "doesn't come up as a controller at all". The manifest declared BLUETOOTH_CONNECT and all three BLE gates tested for it — MainActivity's menu capture, StreamScreen's stream capture, and the Controllers screen — but no code path in the client ever REQUESTED it. It is a runtime permission from API 31, so the checks answered DENIED forever and the BLE transport was unreachable in every shipped build. The failure was silent by construction: `bondedDevices` behind a missing permission throws, and the enumeration caught that into an empty list, which reads exactly like "no controller is paired". - Ask for it, but only of people it helps: an uncaptured SC2 sits in lizard mode as a keyboard/mouse InputDevice, which needs no permission to enumerate, so `sc2InputDevicePresent` is the evidence that justifies the prompt. MainActivity asks once per process on that signal and engages the capture on the grant. - The Controllers screen offers the grant outright, since the probe reads a USB identity we cannot assume a BLE stack reports. `sc2BluetoothGrantOffered` keeps that offer to the cases where it changes something — pure, and table-tested. - Declare the legacy BLUETOOTH permission below API 31. BLUETOOTH_CONNECT does not imply it, so the bonded list and connectGatt would have thrown SecurityException on Android 11 and older even once the runtime half worked. - Gate the link on the permission itself and log when it is missing, so the next occurrence of this says so in logcat instead of looking like an absent controller. Verified: :kit:testDebugUnitTest + :app:testDebugUnitTest green (5 new), manifest merge carries both permissions. On-glass with a BLE-paired SC2 is owed.