System boundary
The phone is the Bluetooth HID device; the PC, TV, or tablet is the host. The app sends keyboard and mouse reports, but it cannot inspect the host's focused field or reliably read its IME mode. That boundary is the reason calibration and host profiles are first-class state rather than UI preferences.
| UI and lifecycle | Kotlin, Jetpack Compose, Android foreground service |
|---|---|
| HID payload | Shared keyboard-and-mouse descriptor with separate report IDs |
| Persistent state | Verified hosts, selected profile, calibration and app preferences |
| Network dependency | None for HID input; ads are a separate optional runtime |
Transport selection
The shared HID layer asks Android for the Classic Bluetooth HID Device profile first. If that profile is unavailable after a bounded grace period, it can select BLE HOGP instead. The chosen transport is published as state so pairing, reconnect, and discoverability rules do not guess which path is active.
- Classic uses Android's HID Device profile and SDP identity.
- BLE HOGP owns a GATT server and has different advertising and reconnect rules.
- The app never runs both transports as independent sessions for one control surface.
- A minimum neutral report verifies that registration alone has become a usable host connection.
Text encoding and host profiles
Text is normalized, divided into English and Korean runs, and compiled into an encoding plan before reports are sent. A modern precomposed Hangul syllable is decomposed into two-set jamo keystrokes; English characters use a US key map. The plan also contains required IME transitions and its final assumed IME state.
The app models, rather than observes, the host IME. Keyboard LED output can refine the assumption on supported hosts, but calibration remains necessary because platforms map language-switch keys differently. The on-screen keycaps are drawn from that same assumption, which is why they can drift out of step with the host.
Profiles make those differences explicit: Windows Korean, Windows US, iOS US, and Android TV US select key maps and mode-switch candidates. Unsupported code points reject the plan before partial text is emitted.
Session ownership and safe release
A foreground service owns registration, host connection, and report dispatch. Keyboard, PPT, and Mouse are separate apps but Android exposes a scarce HID role, so signed sibling apps use a handoff contract: the new owner requests release and the old owner follows its normal shutdown path.
- Input is accepted against a current session token so stale work cannot cross reconnect boundaries.
- Pressed-key state is tracked and neutral reports are sent during normal release.
- Disconnect, unregister, and published UI state follow one ordered shutdown path.
- Recovery can quarantine an uncertain session instead of silently continuing to type.
Verification and known limits
Unit and integration tests cover Hangul decomposition, key maps, encoding plans, descriptor reports, queue ordering, reconnect policy, sibling handoff, process recreation, and calibration decisions. Device behavior still depends on the phone exposing a usable HID transport and the host honoring the advertised descriptor.
- The app cannot guarantee which field has focus on the host.
- The phone's IME indicator can differ from the actual host IME.
- Only characters covered by the selected key maps and modern Hangul plan are sent as text.
- Host applications decide whether horizontal scrolling and special keys have an effect.