diff --git a/echolot-app/adb-beacon/src/main/kotlin/app/echo_lot/adbbeacon/BeaconService.kt b/echolot-app/adb-beacon/src/main/kotlin/app/echo_lot/adbbeacon/BeaconService.kt index dfd2eb7..b18f68f 100644 --- a/echolot-app/adb-beacon/src/main/kotlin/app/echo_lot/adbbeacon/BeaconService.kt +++ b/echolot-app/adb-beacon/src/main/kotlin/app/echo_lot/adbbeacon/BeaconService.kt @@ -38,6 +38,8 @@ class BeaconService : Service() { private var discoveryListener: NsdManager.DiscoveryListener? = null @Volatile private var currentPort: Int = -1 + /** Service instances already resolved — prevents repeat resolves (notification spam). */ + private val resolvedOnce = java.util.Collections.synchronizedSet(mutableSetOf()) private var heartbeat: Job? = null override fun onBind(intent: Intent?): IBinder? = null @@ -47,10 +49,14 @@ class BeaconService : Service() { nsd = getSystemService(Context.NSD_SERVICE) as NsdManager startForeground(1, buildNotification("Starting…")) startDiscovery() + // Re-assert the endpoint periodically, but do NOT re-resolve mDNS each time: + // resolving adbd's own advertisement provokes it to re-arm the connection, which fires + // Android's "wireless debugging connected" notification — every cycle. Discovery runs + // once; we only re-POST the cached port (cheap, silent). heartbeat = scope.launch { while (true) { - report() // refresh seen_at + re-assert current endpoint - delay(20_000) + delay(60_000) + report() } } Status.set("watching for wireless-debug port…") @@ -65,12 +71,18 @@ class BeaconService : Service() { override fun onServiceLost(s: NsdServiceInfo?) { // adbd stops advertising when Wireless debugging is turned off. currentPort = -1 + s?.serviceName?.let { resolvedOnce.remove(it) } // allow one re-resolve when it returns val warn = "⚠ Wireless debugging appears OFF (adb mDNS service gone) — re-enable it" Status.set(warn) updateNotification(warn) } override fun onServiceFound(s: NsdServiceInfo?) { if (s == null) return + // Resolve ONCE per discovered service instance. Repeatedly resolving adbd's own + // advertisement makes it re-arm the connection and spam the user with + // "wireless debugging connected" notifications. + val key = s.serviceName ?: return + if (!resolvedOnce.add(key)) return resolve(s) } }