Skip to content

feat(connections): unified device list + USB address stabilization#5208

Closed
jamesarich wants to merge 5 commits intomainfrom
fix/unified-device-list
Closed

feat(connections): unified device list + USB address stabilization#5208
jamesarich wants to merge 5 commits intomainfrom
fix/unified-device-list

Conversation

@jamesarich
Copy link
Copy Markdown
Collaborator

@jamesarich jamesarich commented Apr 22, 2026

Summary

Connections UI overhaul:

  1. Unified device list — Replaces the tabbed Bluetooth/Network/USB picker with a single Connections screen that ranks bonded BLE, USB (OTG), discovered NSD, and recently-used TCP devices in one adaptive list.
  2. USB address stabilization — Switch from volatile USB device paths to stable usb:VID:PID:SERIAL identifiers so reconnects, recognition, and DB lookups survive replug/reboot.
  3. Connections screen LNP wiring — Wire ACCESS_LOCAL_NETWORK runtime request into the Connections screen so Android 17 NSD discovery doesn't fall back to the system "Choose a device" picker.

Changes by Commit

feat(connections): unified device list + cross-platform discovery overhaul

  • New adaptive DeviceList with M3 section headers and sticky "currently connected" card.
  • Per-transport inline empty states with actionable hints.
  • Device rows show NodeChip for recognized devices, BLE RSSI, and animated reordering.
  • NSD network scanning gated behind user preference to avoid chatty discovery.
  • Device recognition works cross-transport.
  • Nodes screen gets empty state; initial tab gated on device selection.

feat(network): stabilize USB addresses by VID:PID[:SERIAL]

  • USB device paths change on every replug/reboot → switch to stable usb:VID:PID:SERIAL id.
  • Fall back to usb:VID:PID when platform denies serial access (Android <11).
  • UI displays volatile port path as subtitle, stable id used for DB/recognition lookups.
  • Title rendered as Meshtastic · VVVV:PPPP (4-digit upper-case hex).

feat(connections): wire ACCESS_LOCAL_NETWORK request into Connections screen

  • Gate ConnectionsScreen network auto-start on the runtime grant.
  • Manual scan toggle requests the permission before starting; persists user intent for the deferred-start path.
  • Adds ScannerViewModel.persistNetworkAutoScanIntent.

Splits

The polite-disconnect and permission-gating work originally bundled here was moved to:

@github-actions github-actions Bot added the bugfix PR tag label Apr 22, 2026
@jamesarich jamesarich changed the title fix(permissions): gate LOCAL_NETWORK to TAK Server, use core/ui helper fix(permissions): gate LOCAL_NETWORK to TAK Server, deprecate Accompanist Apr 22, 2026
@jamesarich jamesarich changed the title fix(permissions): gate LOCAL_NETWORK to TAK Server, deprecate Accompanist feat(connections): unified device list, USB stabilization, polite disconnect, permission gating Apr 22, 2026
@jamesarich jamesarich marked this pull request as draft April 22, 2026 00:43
jamesarich and others added 2 commits April 22, 2026 09:13
…r instead of Accompanist

- Remove global ACCESS_LOCAL_NETWORK declaration from manifest (only needed for TAK localhost binding)
- Add rememberRequestLocalNetworkPermission to core/ui PlatformUtils API
- Implement for Android (gated to API 31+), iOS/JVM (no-ops)
- Replace Accompanist in TAK permission handler with core/ui helper
- Reduces per-reinstall permission prompts; users only see dialog when enabling TAK
- Consistent with project's existing permission pattern (location/BLE/notifications)
- Net -18 LOC

Fixes unnecessary LOCAL_NETWORK permission dialog on app reinstall when TAK Server is disabled.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s NSD picker

On Android 17 (API 37) with targetSdk=37, the platform falls back to the
system 'Choose a device to connect' picker on every NsdManager.discoverServices()
call when ACCESS_LOCAL_NETWORK isn't granted. Removing the manifest entry in
the previous commit only suppressed the runtime grant flavor of the prompt —
the picker still fires as the platform's mediated fallback.

This restores the manifest declaration and adds an isLocalNetworkPermissionGranted()
helper plus the rememberRequestLocalNetworkPermission Compose helper to core/ui,
ready to be wired into the connections UI. Because ACCESS_LOCAL_NETWORK is in
the NEARBY_DEVICES permission group, users who have already granted Bluetooth
permissions are silently auto-granted with no UI shown.

- Re-add ACCESS_LOCAL_NETWORK to AndroidManifest.xml with comment explaining
  the Android 17 LNP enforcement and dual TAK/NSD use case.
- Add isLocalNetworkPermissionGranted() expect/actual helper to core/ui.
- Update TakPermissionUtil comment — pre-existing comment claimed the
  permission was 'NOT required for NSD', which was true on Android 16 but
  false on Android 17 with targetSdk=37.

The ConnectionsScreen wiring that consumes these helpers is part of the
separate unified-device-list PR (#5208).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jamesarich and others added 3 commits April 22, 2026 09:17
…rhaul

Replaces the tabbed Bluetooth/Network/USB picker with a single Connections
screen that ranks bonded BLE, USB (OTG), discovered NSD, and recently-used
TCP devices in one adaptive list. Gates NSD scanning behind a user pref to
avoid chatty discovery, and makes device recognition work cross-transport.

UI / UX
- New adaptive DeviceList with M3 section headers and a stable, sticky
  "currently connected" card at the top of the screen.
- Per-transport inline empty states with actionable hints instead of one
  generic empty message.
- Device rows now show the NodeChip for recognized devices, BLE RSSI when
  seen, and animated list reordering as RSSI updates.
- New ConnectionActionButton + DisconnectButton components replace ad-hoc
  buttons; new DeviceSectionHeader replaces the old segmented bar.
- Nodes screen gets its own empty state ("no device connected" /
  "searching for nodes") and the initial tab is gated on whether a device
  is currently selected so first-run users land on Connections.
- Android DB detection (DatabaseManager.hasDatabaseFor) now matches files
  without a `.db` extension so USB/serial-keyed DBs are recognized.

Preferences
- AppPreferences gains auto-scan toggles (BLE / NSD) persisted via
  UiPrefsImpl; scanner VM honours them so scanning only runs when the user
  wants it.

Refactors
- Scanner VM + discovery use cases split into Common / Android / JVM
  variants with DRY flow composition; JvmGetDiscoveredDevicesUseCase added
  so desktop compiles without Android scaffolding.
- OTG-attached serial devices now surface immediately in the list via
  UsbBroadcastReceiver plumbing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
USB device paths (`/dev/bus/usb/NNN/MMM`) change on every replug and
after every reboot, which made the per-device Room database and
DeviceListItem subtitle churn. Switch the internal USB address to a
stable `usb:VID:PID:SERIAL` id (falling back to `usb:VID:PID` when the
platform denies serial access pre-permission on Android 10+), keyed in
UsbRepository and threaded through stableUsbId().

UI keeps the volatile port path visible as the row subtitle via a new
DeviceListEntry.displayAddress override, while the stable id is used
internally for DB/recognition lookups. Title is rendered as
`Meshtastic · VVVV:PPPP` (4-digit upper-case hex).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… screen

On Android 17 (API 37) with targetSdk=37, NsdManager.discoverServices() falls
back to the system 'Choose a device to connect' picker on every call when
ACCESS_LOCAL_NETWORK isn't granted. Wire the new core/ui permission helpers
into ConnectionsScreen so users get a proper one-time grant prompt instead of
a per-scan picker. Because ACCESS_LOCAL_NETWORK is in the NEARBY_DEVICES
permission group, users who have already granted Bluetooth permissions are
silently auto-granted with no UI shown.

- Gate ConnectionsScreen network auto-start on the runtime grant so a
  previously-persisted networkAutoScan=true does not surface the picker for
  users who haven't granted the permission.
- Manual scan toggle now requests the permission before starting and persists
  the user's intent so the launcher's onGranted callback can start the scan.
- Add ScannerViewModel.persistNetworkAutoScanIntent for the deferred-start path.

The manifest declaration and core/ui helpers consumed here ship in the separate
permission-gating PR (#5211).

Verified on Pixel 6a / Android 17 / API 37: NSD discovery now runs without the
picker, and the permission is silently auto-granted via the NEARBY_DEVICES
group when Bluetooth perms are already held.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jamesarich jamesarich force-pushed the fix/unified-device-list branch from 901cff4 to fda0e07 Compare April 22, 2026 14:19
@jamesarich jamesarich changed the title feat(connections): unified device list, USB stabilization, polite disconnect, permission gating feat(connections): unified device list + USB address stabilization Apr 22, 2026
@jamesarich jamesarich closed this Apr 22, 2026
@jamesarich jamesarich deleted the fix/unified-device-list branch April 23, 2026 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix PR tag

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant