kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
commit
7e8b7bc833
|
@ -0,0 +1,97 @@
|
|||
package com.geeksville.mesh.repository.nsd
|
||||
|
||||
import android.net.nsd.NsdManager
|
||||
import android.net.nsd.NsdServiceInfo
|
||||
import com.geeksville.android.Logging
|
||||
import com.geeksville.mesh.CoroutineDispatchers
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@Singleton
|
||||
class NsdRepository @Inject constructor(
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
private val nsdManagerLazy: dagger.Lazy<NsdManager?>,
|
||||
) : Logging {
|
||||
|
||||
private val resolveQueue = Semaphore(1)
|
||||
private var hostsList: ArrayList<NsdServiceInfo>? = ArrayList()
|
||||
|
||||
val resolvedList: List<NsdServiceInfo>? get() = hostsList
|
||||
|
||||
private val _networkDiscovery: Flow<NsdServiceInfo> = callbackFlow {
|
||||
val discoveryListener = object : NsdManager.DiscoveryListener {
|
||||
override fun onDiscoveryStarted(regType: String) {
|
||||
debug("Service discovery started: $regType")
|
||||
hostsList?.clear()
|
||||
}
|
||||
|
||||
override fun onServiceFound(service: NsdServiceInfo) {
|
||||
debug("Service discovery success: $service")
|
||||
if (service.serviceType == SERVICE_TYPE &&
|
||||
service.serviceName.contains(serviceName)
|
||||
) {
|
||||
val resolveListener = object : NsdManager.ResolveListener {
|
||||
override fun onServiceResolved(service: NsdServiceInfo) {
|
||||
debug("Resolve Succeeded: $service")
|
||||
hostsList?.add(service)
|
||||
trySend(service)
|
||||
}
|
||||
|
||||
override fun onResolveFailed(service: NsdServiceInfo, errorCode: Int) {
|
||||
debug("Resolve failed: $service - Error code: $errorCode")
|
||||
}
|
||||
}
|
||||
// one resolveService at a time to avoid: Error Code 3: Failure Already active
|
||||
launch {
|
||||
try {
|
||||
resolveQueue.acquire()
|
||||
nsdManagerLazy.get()?.resolveService(service, resolveListener)
|
||||
} finally {
|
||||
resolveQueue.release()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug("Not our Service - Name: ${service.serviceName}, Type: ${service.serviceType}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onServiceLost(service: NsdServiceInfo) {
|
||||
debug("Service lost: $service")
|
||||
}
|
||||
|
||||
override fun onDiscoveryStopped(serviceType: String) {
|
||||
debug("Discovery stopped: $serviceType")
|
||||
}
|
||||
|
||||
override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) {
|
||||
debug("Start Discovery failed: Error code: $errorCode")
|
||||
nsdManagerLazy.get()?.stopServiceDiscovery(this)
|
||||
}
|
||||
|
||||
override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) {
|
||||
debug("Stop Discovery failed: Error code: $errorCode")
|
||||
nsdManagerLazy.get()?.stopServiceDiscovery(this)
|
||||
}
|
||||
}
|
||||
nsdManagerLazy.get()
|
||||
?.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryListener)
|
||||
awaitClose { nsdManagerLazy.get()?.stopServiceDiscovery(discoveryListener) }
|
||||
}.flowOn(dispatchers.default)
|
||||
|
||||
fun networkDiscoveryFlow(): Flow<NsdServiceInfo> {
|
||||
return _networkDiscovery
|
||||
}
|
||||
|
||||
companion object {
|
||||
//To find all the available networks SERVICE_TYPE = "_services._dns-sd._udp"
|
||||
const val SERVICE_TYPE = "_http._tcp."
|
||||
const val serviceName = "Meshtastic"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.geeksville.mesh.repository.nsd
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.net.nsd.NsdManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class NsdRepositoryModule {
|
||||
companion object {
|
||||
@Provides
|
||||
fun provideNsdManager(application: Application): NsdManager? {
|
||||
return application.getSystemService(Context.NSD_SERVICE) as NsdManager?
|
||||
}
|
||||
}
|
||||
}
|
|
@ -87,7 +87,6 @@ class TCPInterface(service: RadioInterfaceService, private val address: String)
|
|||
} else
|
||||
readChar(c.toByte())
|
||||
} catch (ex: SocketTimeoutException) {
|
||||
errormsg("SocketTimeoutException in TCP reader: $ex")
|
||||
// Ignore and start another read
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import com.geeksville.mesh.databinding.SettingsFragmentBinding
|
|||
import com.geeksville.mesh.model.BluetoothViewModel
|
||||
import com.geeksville.mesh.model.UIViewModel
|
||||
import com.geeksville.mesh.repository.bluetooth.BluetoothRepository
|
||||
import com.geeksville.mesh.repository.nsd.NsdRepository
|
||||
import com.geeksville.mesh.repository.radio.MockInterface
|
||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||
import com.geeksville.mesh.repository.radio.SerialInterface
|
||||
|
@ -59,7 +60,11 @@ import com.google.android.material.snackbar.Snackbar
|
|||
import com.hoho.android.usbserial.driver.UsbSerialDriver
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import java.util.regex.Pattern
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -121,7 +126,7 @@ class BTScanModel @Inject constructor(
|
|||
private val application: Application,
|
||||
private val bluetoothRepository: BluetoothRepository,
|
||||
private val usbRepository: UsbRepository,
|
||||
// private val nsdRepository: NsdRepository,
|
||||
private val nsdRepository: NsdRepository,
|
||||
) : ViewModel(), Logging {
|
||||
|
||||
private val context: Context get() = application.applicationContext
|
||||
|
@ -233,6 +238,9 @@ class BTScanModel @Inject constructor(
|
|||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun stopScan() {
|
||||
// Stop Network Service Discovery (for TCP)
|
||||
networkDiscovery?.cancel()
|
||||
|
||||
if (scanner != null) {
|
||||
debug("stopping scan")
|
||||
try {
|
||||
|
@ -288,9 +296,9 @@ class BTScanModel @Inject constructor(
|
|||
addDeviceAssociations()
|
||||
|
||||
// Include Network Service Discovery
|
||||
// nsdRepository.resolvedList?.forEach { service ->
|
||||
// addDevice(TCPDeviceListEntry(service))
|
||||
// }
|
||||
nsdRepository.resolvedList?.forEach { service ->
|
||||
addDevice(TCPDeviceListEntry(service))
|
||||
}
|
||||
|
||||
val serialDevices by lazy { usbRepository.serialDevicesWithDrivers.value }
|
||||
serialDevices.forEach { (_, d) ->
|
||||
|
@ -303,7 +311,13 @@ class BTScanModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun startScan () {
|
||||
private var networkDiscovery: Job? = null
|
||||
fun startScan() {
|
||||
// Start Network Service Discovery (find TCP devices)
|
||||
networkDiscovery = nsdRepository.networkDiscoveryFlow()
|
||||
.onEach { addDevice(TCPDeviceListEntry(it)) }
|
||||
.launchIn(CoroutineScope(Dispatchers.Main))
|
||||
|
||||
if (hasCompanionDeviceApi) {
|
||||
startCompanionScan()
|
||||
} else startClassicScan()
|
||||
|
|
Ładowanie…
Reference in New Issue