mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 07:05:21 +00:00
3a983c5767
* wifi aware wip * wifi aware wip * starting to work * werk * dms work * wip * fix(wifi-aware): use bindSocket and scoped IPv6 instead of bindProcessToNetwork * Merge branch 'upstream/main' into fix/wifi-aware-socket-binding * Fix Wi-Fi Aware connectivity and UI integration post-merge - Replace bindProcessToNetwork with bindSocket for VPN compatibility. - Implement Scoped IPv6 address resolution (aware0) for mesh routing. - Bridge Wi-Fi Aware incoming messages to AppStateStore for UI visibility. - Fix syntax errors and variable name conflicts in Debug UI. * Enhance Wi-Fi Aware robustness and debug UI display - Clean up transport resources (sockets, server sockets, network callbacks) immediately on peer disconnection. - Implement resolveScopedAddress to show scoped IPv6 (e.g., %aware0) in Debug UI. - Fix Map type mismatch warning in ChatViewModel bridge. - Filter self-ID from peer cleanup tables to prevent recursive self-removal. * Share GossipSyncManager across transports to prevent redundant message synchronization - Registered BluetoothMeshService's GossipSyncManager as a singleton in MeshServiceHolder. - Modified WifiAwareMeshService to use the shared GossipSyncManager if available. - Added background cleanup for peer mappings on socket disconnection. - Fixed Kotlin type mismatch during nickname map merging. * Restore VPN acquisition logic and improve peer cleanup - Revert removal of NET_CAPABILITY_NOT_VPN to allow hardware handle acquisition while VPN is active. - Refactor handlePeerDisconnection to more reliably cleanup initial and routed IDs. - Switch cleanup logging to debug level to reduce log noise. * Fix wifi aware socket binding 2 (#536) * Background persistence (#505) * persistence step 1 * fix build * messages in the background work, notifications not yet * app state store * DM icon shows up * notification launches when app is closed! * keep ui updated * lifecycle fixes * extensive logging, maybe revert later * send nickname in announcement * quit in notification * setting in about sheet * fix quit bitchat * lifecycle fixes * power mode based on background state * stats for both direciotns * fix graph persistence * better counting * count per device * only compute when debug sheet is open? untested * fix read receipts * fix read receipts fully * fix unread badge if messages have been read in focus * foreground promotion fix * fix app kill in notification * adjust to new tor * nice * about sheet design * bump version 1.6.0 (#524) * Automated update of relay data - Sun Dec 14 06:06:53 UTC 2025 * bump targetSdk (#526) * Automated update of relay data - Sun Dec 21 06:06:56 UTC 2025 * Automated update of relay data - Sun Dec 28 06:07:12 UTC 2025 * Prevent quit notification from reappearing (#530) * shutdown sequence * Prevent quit notification from reappearing * Restrict force-finish broadcast * Cancel quit shutdown on relaunch * fix(wifi-aware): use bindSocket and scoped IPv6 instead of bindProcessToNetwork * Merge branch 'upstream/main' into fix/wifi-aware-socket-binding * Fix Wi-Fi Aware connectivity and UI integration post-merge - Replace bindProcessToNetwork with bindSocket for VPN compatibility. - Implement Scoped IPv6 address resolution (aware0) for mesh routing. - Bridge Wi-Fi Aware incoming messages to AppStateStore for UI visibility. - Fix syntax errors and variable name conflicts in Debug UI. * Enhance Wi-Fi Aware robustness and debug UI display - Clean up transport resources (sockets, server sockets, network callbacks) immediately on peer disconnection. - Implement resolveScopedAddress to show scoped IPv6 (e.g., %aware0) in Debug UI. - Fix Map type mismatch warning in ChatViewModel bridge. - Filter self-ID from peer cleanup tables to prevent recursive self-removal. * Share GossipSyncManager across transports to prevent redundant message synchronization - Registered BluetoothMeshService's GossipSyncManager as a singleton in MeshServiceHolder. - Modified WifiAwareMeshService to use the shared GossipSyncManager if available. - Added background cleanup for peer mappings on socket disconnection. - Fixed Kotlin type mismatch during nickname map merging. * Restore VPN acquisition logic and improve peer cleanup - Revert removal of NET_CAPABILITY_NOT_VPN to allow hardware handle acquisition while VPN is active. - Refactor handlePeerDisconnection to more reliably cleanup initial and routed IDs. - Switch cleanup logging to debug level to reduce log noise. --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: aidenvalue <> * Fix wifi aware routing (#534) * Background persistence (#505) * persistence step 1 * fix build * messages in the background work, notifications not yet * app state store * DM icon shows up * notification launches when app is closed! * keep ui updated * lifecycle fixes * extensive logging, maybe revert later * send nickname in announcement * quit in notification * setting in about sheet * fix quit bitchat * lifecycle fixes * power mode based on background state * stats for both direciotns * fix graph persistence * better counting * count per device * only compute when debug sheet is open? untested * fix read receipts * fix read receipts fully * fix unread badge if messages have been read in focus * foreground promotion fix * fix app kill in notification * adjust to new tor * nice * about sheet design * bump version 1.6.0 (#524) * Automated update of relay data - Sun Dec 14 06:06:53 UTC 2025 * bump targetSdk (#526) * Automated update of relay data - Sun Dec 21 06:06:56 UTC 2025 * Automated update of relay data - Sun Dec 28 06:07:12 UTC 2025 * Prevent quit notification from reappearing (#530) * shutdown sequence * Prevent quit notification from reappearing * Restrict force-finish broadcast * Cancel quit shutdown on relaunch * fix(wifi-aware): use bindSocket and scoped IPv6 instead of bindProcessToNetwork * Merge branch 'upstream/main' into fix/wifi-aware-socket-binding * Fix Wi-Fi Aware connectivity and UI integration post-merge - Replace bindProcessToNetwork with bindSocket for VPN compatibility. - Implement Scoped IPv6 address resolution (aware0) for mesh routing. - Bridge Wi-Fi Aware incoming messages to AppStateStore for UI visibility. - Fix syntax errors and variable name conflicts in Debug UI. * Enhance Wi-Fi Aware robustness and debug UI display - Clean up transport resources (sockets, server sockets, network callbacks) immediately on peer disconnection. - Implement resolveScopedAddress to show scoped IPv6 (e.g., %aware0) in Debug UI. - Fix Map type mismatch warning in ChatViewModel bridge. - Filter self-ID from peer cleanup tables to prevent recursive self-removal. * Share GossipSyncManager across transports to prevent redundant message synchronization - Registered BluetoothMeshService's GossipSyncManager as a singleton in MeshServiceHolder. - Modified WifiAwareMeshService to use the shared GossipSyncManager if available. - Added background cleanup for peer mappings on socket disconnection. - Fixed Kotlin type mismatch during nickname map merging. * Restore VPN acquisition logic and improve peer cleanup - Revert removal of NET_CAPABILITY_NOT_VPN to allow hardware handle acquisition while VPN is active. - Refactor handlePeerDisconnection to more reliably cleanup initial and routed IDs. - Switch cleanup logging to debug level to reduce log noise. * fix wifi aware routing --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: aidenvalue <> * unify connection tracker for ble and wifi (#537) * unify connection tracker for ble and wifi * cleanup nicely * Wifi aware skip bluetooth (#538) * unify connection tracker for ble and wifi * bluetooth optional * refactor mesh core * tests * share gossip * refresh peer list more often * patches: wifi aware mesh refactor core (#549) * Refactor WifiAware memory management and lifecycle handling * Fix Wi-Fi Aware reconnection by ensuring callback unregistration and session watchdog * fix(wifiaware): allow WifiAwareController to restart service if session drops * Enhance WiFi Aware logging with network request timeouts and detailed callback status * Ensure explicit release of WiFi Aware network callbacks on failure or disconnection --------- Co-authored-by: aidenvalue <> * fix: wifi aware mesh private dms (#561) * fix(wifi-aware): restore peer check and remove aggressive session restarts * synchronized access to sockets. * clear old peer socket `onClientConnected` if one was found. * address second round of review * fix: Restart publish session on termination in WifiAwareMeshService * fix: cleanup connection tracker resources when handling peer disconnection without active socket --------- Co-authored-by: aidenvalu3 <> * fix(mesh): address memory leaks and background persistence issues in Wi-Fi Aware - Move message persistence and background notifications for Wi-Fi Aware into the service layer via MeshCore hooks. - Fix memory leak in MainActivity by properly detaching WifiAwareMeshDelegate on pause. - Ensure BluetoothMeshService is initialized before WifiAwareMeshService to guarantee shared GossipSyncManager instance. - Deduplicate persistence logic from MainActivity delegate. * wifi aware working * more robust * fragments work * new files * wifi improvements * handshake works * improve * wifi mesh more robust * fix review * check for support * wifi aware fixes --------- Co-authored-by: aidenvalue <> Co-authored-by: GitHub Action <action@github.com> Co-authored-by: aidenvalu3 <erendentman@gmail.com> Co-authored-by: a1denvalu3 <43107113+a1denvalu3@users.noreply.github.com> Co-authored-by: CC <cc@ggg.local>
387 lines
16 KiB
Kotlin
387 lines
16 KiB
Kotlin
package com.bitchat.android.mesh
|
|
|
|
import android.content.Context
|
|
import android.util.Log
|
|
import com.bitchat.android.model.BitchatFilePacket
|
|
import com.bitchat.android.model.BitchatMessage
|
|
import com.bitchat.android.noise.NoiseSession
|
|
import com.bitchat.android.wifiaware.WifiAwareController
|
|
|
|
/**
|
|
* Feature-facing mesh service that hides local transport selection from the rest of the app.
|
|
*
|
|
* BLE remains the canonical origin for broadcast packets when it is enabled so existing BLE mesh
|
|
* behavior and bridge semantics stay intact. Addressed Noise traffic is routed over whichever
|
|
* local transport already has the peer/session, falling back to a connected transport handshake.
|
|
*/
|
|
class UnifiedMeshService(
|
|
private val context: Context,
|
|
private val bluetooth: BluetoothMeshService
|
|
) : MeshService, BluetoothMeshDelegate {
|
|
|
|
companion object {
|
|
private const val TAG = "UnifiedMeshService"
|
|
}
|
|
|
|
override val myPeerID: String
|
|
get() = bluetooth.myPeerID
|
|
|
|
override var delegate: MeshDelegate? = null
|
|
set(value) {
|
|
field = value
|
|
refreshDelegates()
|
|
}
|
|
|
|
fun refreshDelegates() {
|
|
try { bluetooth.delegate = if (delegate != null) this else null } catch (_: Exception) { }
|
|
try { wifiService()?.delegate = if (delegate != null) this else null } catch (_: Exception) { }
|
|
}
|
|
|
|
override fun startServices() {
|
|
if (isBleEnabled()) {
|
|
try { bluetooth.startServices() } catch (e: Exception) {
|
|
Log.w(TAG, "Failed to start BLE transport: ${e.message}")
|
|
}
|
|
} else {
|
|
try { bluetooth.setBleTransportEnabled(false) } catch (_: Exception) { }
|
|
}
|
|
try { WifiAwareController.startIfPossible() } catch (e: Exception) {
|
|
Log.w(TAG, "Failed to start Wi-Fi Aware transport: ${e.message}")
|
|
}
|
|
refreshDelegates()
|
|
}
|
|
|
|
override fun stopServices() {
|
|
try { bluetooth.stopServices() } catch (_: Exception) { }
|
|
try { WifiAwareController.stop() } catch (_: Exception) { }
|
|
}
|
|
|
|
override fun sendMessage(content: String, mentions: List<String>, channel: String?) {
|
|
when {
|
|
isBleEnabled() -> bluetooth.sendMessage(content, mentions, channel)
|
|
else -> wifiService()?.sendMessage(content, mentions, channel)
|
|
}
|
|
}
|
|
|
|
override fun sendPrivateMessage(
|
|
content: String,
|
|
recipientPeerID: String,
|
|
recipientNickname: String,
|
|
messageID: String?
|
|
) {
|
|
when {
|
|
isBleReady(recipientPeerID) -> bluetooth.sendPrivateMessage(content, recipientPeerID, recipientNickname, messageID)
|
|
isWifiReady(recipientPeerID) -> wifiService()?.sendPrivateMessage(content, recipientPeerID, recipientNickname, messageID)
|
|
isBleConnected(recipientPeerID) || (isBleEnabled() && !isWifiConnected(recipientPeerID)) ->
|
|
bluetooth.sendPrivateMessage(content, recipientPeerID, recipientNickname, messageID)
|
|
else -> wifiService()?.sendPrivateMessage(content, recipientPeerID, recipientNickname, messageID)
|
|
}
|
|
}
|
|
|
|
override fun sendReadReceipt(messageID: String, recipientPeerID: String, readerNickname: String) {
|
|
when {
|
|
isBleReady(recipientPeerID) -> bluetooth.sendReadReceipt(messageID, recipientPeerID, readerNickname)
|
|
isWifiReady(recipientPeerID) -> wifiService()?.sendReadReceipt(messageID, recipientPeerID, readerNickname)
|
|
}
|
|
}
|
|
|
|
override fun sendFavoriteNotification(peerID: String, isFavorite: Boolean) {
|
|
val myNpub = try {
|
|
com.bitchat.android.nostr.NostrIdentityBridge.getCurrentNostrIdentity(context)?.npub
|
|
} catch (_: Exception) {
|
|
null
|
|
}
|
|
val content = if (isFavorite) "[FAVORITED]:${myNpub ?: ""}" else "[UNFAVORITED]:${myNpub ?: ""}"
|
|
val nickname = getPeerNicknames()[peerID] ?: peerID
|
|
if (hasEstablishedSession(peerID)) {
|
|
sendPrivateMessage(content, peerID, nickname, java.util.UUID.randomUUID().toString())
|
|
}
|
|
}
|
|
|
|
override fun sendVerifyChallenge(peerID: String, noiseKeyHex: String, nonceA: ByteArray) {
|
|
when {
|
|
isBleReady(peerID) -> bluetooth.sendVerifyChallenge(peerID, noiseKeyHex, nonceA)
|
|
isWifiReady(peerID) -> wifiService()?.sendVerifyChallenge(peerID, noiseKeyHex, nonceA)
|
|
}
|
|
}
|
|
|
|
override fun sendVerifyResponse(peerID: String, noiseKeyHex: String, nonceA: ByteArray) {
|
|
when {
|
|
isBleReady(peerID) -> bluetooth.sendVerifyResponse(peerID, noiseKeyHex, nonceA)
|
|
isWifiReady(peerID) -> wifiService()?.sendVerifyResponse(peerID, noiseKeyHex, nonceA)
|
|
}
|
|
}
|
|
|
|
override fun sendFileBroadcast(file: BitchatFilePacket) {
|
|
when {
|
|
isBleEnabled() -> bluetooth.sendFileBroadcast(file)
|
|
else -> wifiService()?.sendFileBroadcast(file)
|
|
}
|
|
}
|
|
|
|
override fun sendFilePrivate(recipientPeerID: String, file: BitchatFilePacket) {
|
|
when {
|
|
isBleReady(recipientPeerID) -> bluetooth.sendFilePrivate(recipientPeerID, file)
|
|
isWifiReady(recipientPeerID) -> wifiService()?.sendFilePrivate(recipientPeerID, file)
|
|
isBleConnected(recipientPeerID) || (isBleEnabled() && !isWifiConnected(recipientPeerID)) ->
|
|
bluetooth.sendFilePrivate(recipientPeerID, file)
|
|
else -> wifiService()?.sendFilePrivate(recipientPeerID, file)
|
|
}
|
|
}
|
|
|
|
override fun cancelFileTransfer(transferId: String): Boolean {
|
|
val bleCancelled = try { bluetooth.cancelFileTransfer(transferId) } catch (_: Exception) { false }
|
|
val wifiCancelled = try { wifiService()?.cancelFileTransfer(transferId) == true } catch (_: Exception) { false }
|
|
return bleCancelled || wifiCancelled
|
|
}
|
|
|
|
override fun sendBroadcastAnnounce() {
|
|
if (isBleEnabled()) {
|
|
try { bluetooth.sendBroadcastAnnounce() } catch (_: Exception) { }
|
|
}
|
|
try { wifiService()?.sendBroadcastAnnounce() } catch (_: Exception) { }
|
|
}
|
|
|
|
override fun sendAnnouncementToPeer(peerID: String) {
|
|
when {
|
|
isBleConnected(peerID) || (isBleEnabled() && !isWifiConnected(peerID)) -> bluetooth.sendAnnouncementToPeer(peerID)
|
|
else -> wifiService()?.sendAnnouncementToPeer(peerID)
|
|
}
|
|
}
|
|
|
|
override fun getPeerNicknames(): Map<String, String> {
|
|
val merged = linkedMapOf<String, String>()
|
|
try { merged.putAll(wifiService()?.getPeerNicknames().orEmpty()) } catch (_: Exception) { }
|
|
try { merged.putAll(bluetooth.getPeerNicknames()) } catch (_: Exception) { }
|
|
return merged
|
|
}
|
|
|
|
override fun getPeerRSSI(): Map<String, Int> {
|
|
val merged = linkedMapOf<String, Int>()
|
|
try { merged.putAll(wifiService()?.getPeerRSSI().orEmpty()) } catch (_: Exception) { }
|
|
try { merged.putAll(bluetooth.getPeerRSSI()) } catch (_: Exception) { }
|
|
return merged
|
|
}
|
|
|
|
override fun getActivePeerCount(): Int {
|
|
return mergedPeerIDs().filter { it != myPeerID }.distinct().size
|
|
}
|
|
|
|
override fun hasEstablishedSession(peerID: String): Boolean {
|
|
return isBleReady(peerID) || isWifiReady(peerID)
|
|
}
|
|
|
|
override fun getSessionState(peerID: String): NoiseSession.NoiseSessionState {
|
|
val bleState = try { bluetooth.getSessionState(peerID) } catch (_: Exception) { NoiseSession.NoiseSessionState.Uninitialized }
|
|
val wifiState = try { wifiService()?.getSessionState(peerID) } catch (_: Exception) { null }
|
|
return when {
|
|
bleState is NoiseSession.NoiseSessionState.Established -> bleState
|
|
wifiState is NoiseSession.NoiseSessionState.Established -> wifiState
|
|
bleState is NoiseSession.NoiseSessionState.Handshaking -> bleState
|
|
wifiState is NoiseSession.NoiseSessionState.Handshaking -> wifiState
|
|
bleState !is NoiseSession.NoiseSessionState.Uninitialized -> bleState
|
|
wifiState != null -> wifiState
|
|
else -> bleState
|
|
}
|
|
}
|
|
|
|
override fun initiateNoiseHandshake(peerID: String) {
|
|
when {
|
|
isBleConnected(peerID) -> bluetooth.initiateNoiseHandshake(peerID)
|
|
isWifiConnected(peerID) -> wifiService()?.initiateNoiseHandshake(peerID)
|
|
isBleEnabled() -> bluetooth.initiateNoiseHandshake(peerID)
|
|
else -> wifiService()?.initiateNoiseHandshake(peerID)
|
|
}
|
|
}
|
|
|
|
override fun getPeerFingerprint(peerID: String): String? {
|
|
return try { bluetooth.getPeerFingerprint(peerID) } catch (_: Exception) { null }
|
|
?: try { wifiService()?.getPeerFingerprint(peerID) } catch (_: Exception) { null }
|
|
}
|
|
|
|
override fun getPeerInfo(peerID: String): PeerInfo? {
|
|
val ble = try { bluetooth.getPeerInfo(peerID) } catch (_: Exception) { null }
|
|
val wifi = try { wifiService()?.getPeerInfo(peerID) } catch (_: Exception) { null }
|
|
return when {
|
|
ble?.isConnected == true && hasEstablishedSessionOnBluetooth(peerID) -> ble
|
|
wifi?.isConnected == true && wifiService()?.hasEstablishedSession(peerID) == true -> wifi
|
|
ble?.isConnected == true -> ble
|
|
wifi?.isConnected == true -> wifi
|
|
else -> ble ?: wifi
|
|
}
|
|
}
|
|
|
|
override fun updatePeerInfo(
|
|
peerID: String,
|
|
nickname: String,
|
|
noisePublicKey: ByteArray,
|
|
signingPublicKey: ByteArray,
|
|
isVerified: Boolean
|
|
): Boolean {
|
|
val bleUpdated = try {
|
|
bluetooth.updatePeerInfo(peerID, nickname, noisePublicKey, signingPublicKey, isVerified)
|
|
} catch (_: Exception) {
|
|
false
|
|
}
|
|
val wifiUpdated = try {
|
|
wifiService()?.updatePeerInfo(peerID, nickname, noisePublicKey, signingPublicKey, isVerified) == true
|
|
} catch (_: Exception) {
|
|
false
|
|
}
|
|
return bleUpdated || wifiUpdated
|
|
}
|
|
|
|
override fun getIdentityFingerprint(): String = bluetooth.getIdentityFingerprint()
|
|
|
|
override fun getStaticNoisePublicKey(): ByteArray? {
|
|
return bluetooth.getStaticNoisePublicKey() ?: wifiService()?.getStaticNoisePublicKey()
|
|
}
|
|
|
|
override fun shouldShowEncryptionIcon(peerID: String): Boolean {
|
|
return hasEstablishedSession(peerID)
|
|
}
|
|
|
|
override fun getEncryptedPeers(): List<String> {
|
|
val encrypted = linkedSetOf<String>()
|
|
try { encrypted.addAll(bluetooth.getEncryptedPeers()) } catch (_: Exception) { }
|
|
try { encrypted.addAll(wifiService()?.getEncryptedPeers().orEmpty()) } catch (_: Exception) { }
|
|
mergedPeerIDs().filterTo(encrypted) { hasEstablishedSession(it) }
|
|
return encrypted.toList()
|
|
}
|
|
|
|
override fun getDeviceAddressForPeer(peerID: String): String? {
|
|
return try { bluetooth.getDeviceAddressForPeer(peerID) } catch (_: Exception) { null }
|
|
?: try { wifiService()?.getDeviceAddressForPeer(peerID) } catch (_: Exception) { null }
|
|
}
|
|
|
|
override fun getDeviceAddressToPeerMapping(): Map<String, String> {
|
|
val merged = linkedMapOf<String, String>()
|
|
try { merged.putAll(wifiService()?.getDeviceAddressToPeerMapping().orEmpty()) } catch (_: Exception) { }
|
|
try { merged.putAll(bluetooth.getDeviceAddressToPeerMapping()) } catch (_: Exception) { }
|
|
return merged
|
|
}
|
|
|
|
override fun printDeviceAddressesForPeers(): String {
|
|
return buildString {
|
|
appendLine(bluetooth.printDeviceAddressesForPeers())
|
|
wifiService()?.let {
|
|
appendLine()
|
|
appendLine(it.printDeviceAddressesForPeers())
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun getDebugStatus(): String {
|
|
return buildString {
|
|
appendLine("=== Unified Mesh Service Debug Status ===")
|
|
appendLine("My Peer ID: $myPeerID")
|
|
appendLine("Merged Peers: ${mergedPeerIDs().joinToString(", ")}")
|
|
appendLine()
|
|
appendLine(bluetooth.getDebugStatus())
|
|
wifiService()?.let {
|
|
appendLine()
|
|
appendLine(it.getDebugStatus())
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun clearAllInternalData() {
|
|
try { bluetooth.clearAllInternalData() } catch (_: Exception) { }
|
|
try { wifiService()?.clearAllInternalData() } catch (_: Exception) { }
|
|
}
|
|
|
|
override fun clearAllEncryptionData() {
|
|
try { bluetooth.clearAllEncryptionData() } catch (_: Exception) { }
|
|
try { wifiService()?.clearAllEncryptionData() } catch (_: Exception) { }
|
|
}
|
|
|
|
override fun didReceiveMessage(message: BitchatMessage) {
|
|
delegate?.didReceiveMessage(message)
|
|
}
|
|
|
|
override fun didUpdatePeerList(peers: List<String>) {
|
|
delegate?.didUpdatePeerList(mergedPeerIDs().ifEmpty { peers.distinct() })
|
|
}
|
|
|
|
override fun didReceiveChannelLeave(channel: String, fromPeer: String) {
|
|
delegate?.didReceiveChannelLeave(channel, fromPeer)
|
|
}
|
|
|
|
override fun didReceiveDeliveryAck(messageID: String, recipientPeerID: String) {
|
|
delegate?.didReceiveDeliveryAck(messageID, recipientPeerID)
|
|
}
|
|
|
|
override fun didReceiveReadReceipt(messageID: String, recipientPeerID: String) {
|
|
delegate?.didReceiveReadReceipt(messageID, recipientPeerID)
|
|
}
|
|
|
|
override fun didReceiveVerifyChallenge(peerID: String, payload: ByteArray, timestampMs: Long) {
|
|
delegate?.didReceiveVerifyChallenge(peerID, payload, timestampMs)
|
|
}
|
|
|
|
override fun didReceiveVerifyResponse(peerID: String, payload: ByteArray, timestampMs: Long) {
|
|
delegate?.didReceiveVerifyResponse(peerID, payload, timestampMs)
|
|
}
|
|
|
|
override fun decryptChannelMessage(encryptedContent: ByteArray, channel: String): String? {
|
|
return delegate?.decryptChannelMessage(encryptedContent, channel)
|
|
}
|
|
|
|
override fun getNickname(): String? = delegate?.getNickname()
|
|
|
|
override fun isFavorite(peerID: String): Boolean = delegate?.isFavorite(peerID) ?: false
|
|
|
|
private fun mergedPeerIDs(): List<String> {
|
|
val ids = linkedSetOf<String>()
|
|
try { ids.addAll(com.bitchat.android.services.AppStateStore.peers.value) } catch (_: Exception) { }
|
|
try { ids.addAll(bluetooth.getPeerNicknames().keys) } catch (_: Exception) { }
|
|
try { ids.addAll(wifiService()?.getPeerNicknames()?.keys.orEmpty()) } catch (_: Exception) { }
|
|
return ids.toList()
|
|
}
|
|
|
|
private fun wifiService(): MeshService? {
|
|
return try {
|
|
WifiAwareController.getService()?.also { service ->
|
|
if (delegate != null && service.delegate !== this) {
|
|
service.delegate = this
|
|
}
|
|
}
|
|
} catch (_: Exception) {
|
|
null
|
|
}
|
|
}
|
|
|
|
private fun isBleEnabled(): Boolean {
|
|
return try {
|
|
com.bitchat.android.ui.debug.DebugSettingsManager.getInstance().bleEnabled.value
|
|
} catch (_: Exception) {
|
|
try { com.bitchat.android.ui.debug.DebugPreferenceManager.getBleEnabled(true) } catch (_: Exception) { true }
|
|
}
|
|
}
|
|
|
|
private fun isBleConnected(peerID: String): Boolean {
|
|
return try { bluetooth.getPeerInfo(peerID)?.isConnected == true } catch (_: Exception) { false }
|
|
}
|
|
|
|
private fun isWifiConnected(peerID: String): Boolean {
|
|
return try { wifiService()?.getPeerInfo(peerID)?.isConnected == true } catch (_: Exception) { false }
|
|
}
|
|
|
|
private fun isBleReady(peerID: String): Boolean {
|
|
return isBleConnected(peerID) && hasEstablishedSessionOnBluetooth(peerID)
|
|
}
|
|
|
|
private fun isWifiReady(peerID: String): Boolean {
|
|
return try {
|
|
val wifi = wifiService()
|
|
wifi?.getPeerInfo(peerID)?.isConnected == true && wifi.hasEstablishedSession(peerID)
|
|
} catch (_: Exception) {
|
|
false
|
|
}
|
|
}
|
|
|
|
private fun hasEstablishedSessionOnBluetooth(peerID: String): Boolean {
|
|
return try { bluetooth.hasEstablishedSession(peerID) } catch (_: Exception) { false }
|
|
}
|
|
}
|