From 095540efc2a76142e6dbdd5d02f66ce8cc8fcffd Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Mon, 22 Jun 2026 23:48:45 +0200 Subject: [PATCH] feat(android): native mDNS discovery, host naming, touch mouse, stock selects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discovery: replace the flaky per-OEM NsdManager with the same mdns-sd browse the Linux/Windows clients use, in the Rust core over JNI and polled by Kotlin (discovery.rs + nativeDiscovery{Start,Poll,Stop}); Kotlin keeps only the Wi-Fi MulticastLock + permission UX. IPv4-only (the core can't dial a bare/scoped v6 literal); daemon + fold-thread cleanup on every failure path; field sanitization so a rogue advert can't corrupt the picker snapshot. Discovery now starts regardless of NEARBY_WIFI_DEVICES (raw multicast only needs the MulticastLock) — a denial no longer kills it forever. ParseTxtTest replaced by ParseRecordTest. Hosts: hide already-saved hosts from the "Discovered" section (match by fingerprint, else address:port — mirrors the Apple client); add an optional Name field to the Add-host sheet and a Rename action on saved cards. Input: touch -> absolute mouse "direct pointing" like the Apple client — the host cursor follows the finger (new nativeSendPointerAbs -> MouseMoveAbs). Tap = left click, two-finger tap = right click, two-finger drag = scroll, tap-then-drag = left-drag, three-finger tap = HUD toggle. Settings: revert the dropdowns to the stock ExposedDropdownMenuBox look (a controller-focus UI will come separately); even out the Add-host field gaps. Docs updated (CLAUDE.md, client READMEs, docs-site status). Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 4 +- Cargo.lock | 1 + clients/android/README.md | 9 +- .../android/app/src/main/AndroidManifest.xml | 6 +- .../kotlin/io/unom/punktfunk/ConnectScreen.kt | 116 +++++-- .../io/unom/punktfunk/SettingsScreen.kt | 58 ++-- .../kotlin/io/unom/punktfunk/StreamScreen.kt | 123 +++++-- .../punktfunk/components/HostComponents.kt | 30 +- .../io/unom/punktfunk/kit/NativeBridge.kt | 28 ++ .../punktfunk/kit/discovery/HostDiscovery.kt | 226 +++++-------- .../punktfunk/kit/security/KnownHostStore.kt | 6 + .../kit/discovery/ParseRecordTest.kt | 62 ++++ .../punktfunk/kit/discovery/ParseTxtTest.kt | 63 ---- clients/android/native/Cargo.toml | 6 + clients/android/native/src/discovery.rs | 303 ++++++++++++++++++ clients/android/native/src/lib.rs | 13 +- clients/android/native/src/session.rs | 32 ++ docs-site/content/docs/status.md | 2 +- 18 files changed, 782 insertions(+), 306 deletions(-) create mode 100644 clients/android/kit/src/test/kotlin/io/unom/punktfunk/kit/discovery/ParseRecordTest.kt delete mode 100644 clients/android/kit/src/test/kotlin/io/unom/punktfunk/kit/discovery/ParseTxtTest.kt create mode 100644 clients/android/native/src/discovery.rs diff --git a/CLAUDE.md b/CLAUDE.md index a4d0f05..562996f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -199,7 +199,9 @@ Low-latency desktop/game streaming stack, Linux-first, with a shared Rust protoc `punktfunk-core`; phone + Android TV): NDK `AMediaCodec` hardware HEVC decode → `SurfaceView` incl. **HDR10** (Main10/BT.2020 PQ) with low-latency tuning + a live stats HUD (`decode.rs`/`stats.rs`), Opus/Oboe audio + mic uplink (`audio.rs`/`mic.rs`), gamepad input with rumble/HID feedback - (`feedback.rs`), `NsdManager` mDNS discovery, SPAKE2 PIN pairing + TOFU (Keystore identity + + (`feedback.rs`), **native `mdns-sd` mDNS discovery** (`discovery.rs`, polled over JNI — the same + browse the Linux/Windows clients use, replacing the flaky per-OEM `NsdManager`; Kotlin keeps only + the `MulticastLock` + permission UX), SPAKE2 PIN pairing + TOFU (Keystore identity + known-host store), Compose UI (Connect/Settings/Stream) with D-pad/controller focus nav. Built for `arm64-v8a` + `x86_64`; published to Google Play (Internal Testing) via `android.yml` (`ci/play-upload.py`). Next: real-device gamepad/HDR live-verify, presenter/latency polish. diff --git a/Cargo.lock b/Cargo.lock index 0469fd7..9d25097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2547,6 +2547,7 @@ dependencies = [ "jni", "libc", "log", + "mdns-sd", "ndk", "opus", "punktfunk-core", diff --git a/clients/android/README.md b/clients/android/README.md index 92fe991..8f54da5 100644 --- a/clients/android/README.md +++ b/clients/android/README.md @@ -11,8 +11,8 @@ machine, trust logic) instead of re-porting it into Kotlin. | Side | Owns | |------|------| -| **Rust** (`clients/android/native` → `libpunktfunk_android.so`) | the JNI seam, `NativeClient` (QUIC control + UDP data plane), AnnexB→`AMediaCodec` decode, Opus+Oboe audio, VK keymap, latency math, trust/pairing | -| **Kotlin** (`clients/android`) | Compose UI (host grid / settings / stream), `SurfaceView` lifecycle, input capture, `NsdManager` discovery, Keystore identity, permissions | +| **Rust** (`clients/android/native` → `libpunktfunk_android.so`) | the JNI seam, `NativeClient` (QUIC control + UDP data plane), AnnexB→`AMediaCodec` decode, Opus+Oboe audio, VK keymap, latency math, trust/pairing, **mDNS discovery** (`mdns-sd`, the same browse the Linux/Windows clients use) | +| **Kotlin** (`clients/android`) | Compose UI (host grid / settings / stream), `SurfaceView` lifecycle, input capture, the Wi-Fi `MulticastLock` + permission UX, Keystore identity, permissions | The single seam is `io.unom.punktfunk.kit.NativeBridge` ⇄ `Java_io_unom_punktfunk_kit_NativeBridge_*`. @@ -30,7 +30,7 @@ clients/android/native/ Rust cdylib (workspace member) — links punktf clients/android/ Gradle project (this dir) settings.gradle.kts · build.gradle.kts · gradle.properties · gradlew app/ :app — Compose UI: Connect / Settings / Stream screens (phone + TV) - kit/ :kit — NativeBridge · discovery (NsdManager) · Gamepad · Keymap · + kit/ :kit — NativeBridge · discovery (native mdns-sd, polled) · Gamepad · Keymap · security (Keystore identity + known-host store) · cargo-ndk build ``` @@ -74,7 +74,8 @@ streaming experience: - **Audio** — Opus + Oboe playback with a jitter ring, plus mic uplink to the host. - **Input** — game controllers (buttons + axes) with rumble and HID feedback; D-pad / game-controller focus navigation for the couch (TV + phone). -- **Discovery & trust** — `NsdManager` mDNS host list, SPAKE2 PIN pairing and TOFU, with a +- **Discovery & trust** — native `mdns-sd` mDNS host list (polled over JNI; the same browse the + Linux/Windows clients use, not `NsdManager`), SPAKE2 PIN pairing and TOFU, with a Keystore-wrapped client identity and a known-host store. - **UI** — Compose host list / settings / stream screens, Material You theming. - **Shipping** — built for `arm64-v8a` + `x86_64`; published to Google Play (Internal Testing). diff --git a/clients/android/app/src/main/AndroidManifest.xml b/clients/android/app/src/main/AndroidManifest.xml index 310de54..4cadcfb 100644 --- a/clients/android/app/src/main/AndroidManifest.xml +++ b/clients/android/app/src/main/AndroidManifest.xml @@ -4,11 +4,13 @@ - + - +