diff --git a/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionManager.kt b/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionManager.kt index f6dc194d..db1745f5 100644 --- a/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionManager.kt +++ b/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionManager.kt @@ -85,10 +85,6 @@ class BluetoothConnectionManager( // Public property for address-peer mapping val addressPeerMap get() = connectionTracker.addressPeerMap - // Expose first-announce helpers to higher layers - fun noteAnnounceReceived(address: String) { connectionTracker.noteAnnounceReceived(address) } - fun hasSeenFirstAnnounce(address: String): Boolean = connectionTracker.hasSeenFirstAnnounce(address) - init { powerManager.delegate = this // Observe debug settings to enforce role state while active diff --git a/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionTracker.kt b/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionTracker.kt index 85e5f452..7e022f33 100644 --- a/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionTracker.kt +++ b/app/src/main/java/com/bitchat/android/mesh/BluetoothConnectionTracker.kt @@ -30,8 +30,6 @@ class BluetoothConnectionTracker( private val connectedDevices = ConcurrentHashMap() private val subscribedDevices = CopyOnWriteArrayList() val addressPeerMap = ConcurrentHashMap() - // Track whether we have seen the first ANNOUNCE on a given device connection - private val firstAnnounceSeen = ConcurrentHashMap() // RSSI tracking from scan results (for devices we discover but may connect as servers) private val scanRSSI = ConcurrentHashMap() @@ -93,8 +91,6 @@ class BluetoothConnectionTracker( Log.d(TAG, "Tracker: Adding device connection for $deviceAddress (isClient: ${deviceConn.isClient}") connectedDevices[deviceAddress] = deviceConn pendingConnections.remove(deviceAddress) - // Mark as awaiting first ANNOUNCE on this connection - firstAnnounceSeen[deviceAddress] = false } /** @@ -323,7 +319,6 @@ class BluetoothConnectionTracker( subscribedDevices.removeAll { it.address == deviceAddress } addressPeerMap.remove(deviceAddress) } - firstAnnounceSeen.remove(deviceAddress) Log.d(TAG, "Cleaned up device connection for $deviceAddress") } @@ -357,23 +352,8 @@ class BluetoothConnectionTracker( addressPeerMap.clear() pendingConnections.clear() scanRSSI.clear() - firstAnnounceSeen.clear() } - /** - * Mark that we have received the first ANNOUNCE over this device connection. - */ - fun noteAnnounceReceived(deviceAddress: String) { - firstAnnounceSeen[deviceAddress] = true - } - - /** - * Check whether the first ANNOUNCE has been seen for a device connection. - */ - fun hasSeenFirstAnnounce(deviceAddress: String): Boolean { - return firstAnnounceSeen[deviceAddress] == true - } - /** * Start periodic cleanup of expired connections */ diff --git a/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt b/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt index 600ff170..f5289878 100644 --- a/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt +++ b/app/src/main/java/com/bitchat/android/mesh/BluetoothMeshService.kt @@ -464,21 +464,24 @@ class BluetoothMeshService(private val context: Context) { // Process the announce val isFirst = messageHandler.handleAnnounce(routed) - // Map device address -> peerID on first announce seen over this device connection + // Map device address -> peerID based on TTL (max TTL = direct neighbor) + // Matches iOS logic: any announce with max TTL on a link defines the direct peer val deviceAddress = routed.relayAddress val pid = routed.peerID if (deviceAddress != null && pid != null) { - // First ANNOUNCE over a device connection defines a direct neighbor. - if (!connectionManager.hasSeenFirstAnnounce(deviceAddress)) { + // Check if this is a direct connection (MAX TTL) + // Note: packet.ttl is UByte, compare with AppConstants.MESSAGE_TTL_HOPS + val isDirect = routed.packet.ttl == com.bitchat.android.util.AppConstants.MESSAGE_TTL_HOPS + + if (isDirect) { // Bind or rebind this device address to the announcing peer connectionManager.addressPeerMap[deviceAddress] = pid - connectionManager.noteAnnounceReceived(deviceAddress) - Log.d(TAG, "Mapped device $deviceAddress to peer $pid on FIRST-ANNOUNCE for this connection") + Log.d(TAG, "Mapped device $deviceAddress to peer $pid (TTL=${routed.packet.ttl})") - // Mark as directly connected (upgrades from routed if needed) + // Mark as directly connected try { peerManager.setDirectConnection(pid, true) } catch (_: Exception) { } - // Initial sync for this newly direct peer + // Initial sync for this direct peer try { gossipSyncManager.scheduleInitialSyncToPeer(pid, 1_000) } catch (_: Exception) { } } } diff --git a/docs/device_manager.md b/docs/device_manager.md index 092403b0..c42cd2c5 100644 --- a/docs/device_manager.md +++ b/docs/device_manager.md @@ -38,7 +38,6 @@ Timers: - Added a `DeviceMonitoringManager` instance and provided a `disconnectCallback` that: - disconnects client GATT connections via `BluetoothConnectionTracker`. - cancels server connections via `BluetoothGattServer.cancelConnection`. -- Exposed `noteAnnounceReceived(address)` as a small helper for higher layers. - Updated `componentDelegate.onPacketReceived` to notify per-device activity to the monitor. 2) GATT Client @@ -59,7 +58,6 @@ Timers: 4) ANNOUNCE Binding - File: `BluetoothMeshService.kt` (in the ANNOUNCE handler where we first map device → peer) -- After mapping a device address to a peer on first verified ANNOUNCE, call `connectionManager.noteAnnounceReceived(address)` to cancel the 15s timer for that device. ## Behavior Summary