fix: improve location querying

closes #498
This commit is contained in:
Zane Schepke 2024-12-21 22:14:31 -05:00
parent fe45a2fad9
commit 25b986ef2f
9 changed files with 284 additions and 189 deletions

View File

@ -0,0 +1,15 @@
package com.zaneschepke.wireguardautotunnel.module
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Wifi
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class MobileData
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Ethernet

View File

@ -13,15 +13,19 @@ import dagger.hilt.android.scopes.ServiceScoped
@Module @Module
@InstallIn(ServiceComponent::class) @InstallIn(ServiceComponent::class)
abstract class ServiceModule { abstract class ServiceModule {
@Binds
@ServiceScoped
abstract fun provideWifiService(wifiService: WifiService): NetworkService<WifiService>
@Binds @Binds
@Wifi
@ServiceScoped @ServiceScoped
abstract fun provideMobileDataService(mobileDataService: MobileDataService): NetworkService<MobileDataService> abstract fun provideWifiService(wifiService: WifiService): NetworkService
@Binds @Binds
@MobileData
@ServiceScoped @ServiceScoped
abstract fun provideEthernetService(ethernetService: EthernetService): NetworkService<EthernetService> abstract fun provideMobileDataService(mobileDataService: MobileDataService): NetworkService
@Binds
@Ethernet
@ServiceScoped
abstract fun provideEthernetService(ethernetService: EthernetService): NetworkService
} }

View File

@ -1,7 +1,6 @@
package com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel package com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel
import android.content.Intent import android.content.Intent
import android.net.NetworkCapabilities
import android.os.IBinder import android.os.IBinder
import android.os.PowerManager import android.os.PowerManager
import androidx.core.app.ServiceCompat import androidx.core.app.ServiceCompat
@ -13,17 +12,16 @@ import com.zaneschepke.wireguardautotunnel.data.domain.Settings
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.module.AppShell import com.zaneschepke.wireguardautotunnel.module.AppShell
import com.zaneschepke.wireguardautotunnel.module.Ethernet
import com.zaneschepke.wireguardautotunnel.module.IoDispatcher import com.zaneschepke.wireguardautotunnel.module.IoDispatcher
import com.zaneschepke.wireguardautotunnel.module.MainImmediateDispatcher import com.zaneschepke.wireguardautotunnel.module.MainImmediateDispatcher
import com.zaneschepke.wireguardautotunnel.module.MobileData
import com.zaneschepke.wireguardautotunnel.module.Wifi
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelEvent import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelEvent
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelState import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelState
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.NetworkState import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.NetworkState
import com.zaneschepke.wireguardautotunnel.service.network.EthernetService
import com.zaneschepke.wireguardautotunnel.service.network.MobileDataService
import com.zaneschepke.wireguardautotunnel.service.network.NetworkService import com.zaneschepke.wireguardautotunnel.service.network.NetworkService
import com.zaneschepke.wireguardautotunnel.service.network.NetworkStatus
import com.zaneschepke.wireguardautotunnel.service.network.WifiService
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationAction import com.zaneschepke.wireguardautotunnel.service.notification.NotificationAction
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
import com.zaneschepke.wireguardautotunnel.service.notification.WireGuardNotification import com.zaneschepke.wireguardautotunnel.service.notification.WireGuardNotification
@ -31,7 +29,6 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.util.Constants import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs
import com.zaneschepke.wireguardautotunnel.util.extensions.cancelWithMessage import com.zaneschepke.wireguardautotunnel.util.extensions.cancelWithMessage
import com.zaneschepke.wireguardautotunnel.util.extensions.getCurrentWifiName
import com.zaneschepke.wireguardautotunnel.util.extensions.isReachable import com.zaneschepke.wireguardautotunnel.util.extensions.isReachable
import com.zaneschepke.wireguardautotunnel.util.extensions.onNotRunning import com.zaneschepke.wireguardautotunnel.util.extensions.onNotRunning
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -64,13 +61,16 @@ class AutoTunnelService : LifecycleService() {
lateinit var rootShell: Provider<RootShell> lateinit var rootShell: Provider<RootShell>
@Inject @Inject
lateinit var wifiService: NetworkService<WifiService> @Wifi
lateinit var wifiService: NetworkService
@Inject @Inject
lateinit var mobileDataService: NetworkService<MobileDataService> @MobileData
lateinit var mobileDataService: NetworkService
@Inject @Inject
lateinit var ethernetService: NetworkService<EthernetService> @Ethernet
lateinit var ethernetService: NetworkService
@Inject @Inject
lateinit var appDataRepository: Provider<AppDataRepository> lateinit var appDataRepository: Provider<AppDataRepository>
@ -242,6 +242,7 @@ class AutoTunnelService : LifecycleService() {
) { double, networkState -> ) { double, networkState ->
AutoTunnelState(tunnelService.get().vpnState.value, networkState, double.first, double.second) AutoTunnelState(tunnelService.get().vpnState.value, networkState, double.first, double.second)
}.collect { state -> }.collect { state ->
Timber.d("Network state: ${state.networkState}")
autoTunnelStateFlow.update { autoTunnelStateFlow.update {
it.copy(vpnState = state.vpnState, networkState = state.networkState, settings = state.settings, tunnels = state.tunnels) it.copy(vpnState = state.vpnState, networkState = state.networkState, settings = state.settings, tunnels = state.tunnels)
} }
@ -256,19 +257,14 @@ class AutoTunnelService : LifecycleService() {
@OptIn(FlowPreview::class) @OptIn(FlowPreview::class)
private fun combineNetworkEventsJob(): Flow<NetworkState> { private fun combineNetworkEventsJob(): Flow<NetworkState> {
return combine( return combine(
wifiService.networkStatus, wifiService.status,
mobileDataService.networkStatus, mobileDataService.status,
ethernetService.networkStatus, ) { wifi, mobileData ->
) { wifi, mobileData, ethernet ->
NetworkState( NetworkState(
wifi.isConnected, wifi.available,
mobileData.isConnected, mobileData.available,
ethernet.isConnected, false,
when (wifi) { wifi.name
is NetworkStatus.CapabilitiesChanged -> getWifiSSID(wifi.networkCapabilities)
is NetworkStatus.Available -> autoTunnelStateFlow.value.networkState.wifiName
is NetworkStatus.Unavailable -> null
},
) )
}.distinctUntilChanged().filterNot { it.isWifiConnected && it.wifiName == null }.debounce(500L) }.distinctUntilChanged().filterNot { it.isWifiConnected && it.wifiName == null }.debounce(500L)
} }
@ -285,28 +281,6 @@ class AutoTunnelService : LifecycleService() {
}.distinctUntilChanged() }.distinctUntilChanged()
} }
private suspend fun getWifiSSID(networkCapabilities: NetworkCapabilities): String? {
return withContext(ioDispatcher) {
val settings = settings()
if (settings.isWifiNameByShellEnabled) return@withContext rootShell.get().getCurrentWifiName()
wifiService.getNetworkName(networkCapabilities)
}.also {
if (it?.contains(Constants.UNREADABLE_SSID) == true) {
Timber.w("SSID unreadable: missing permissions")
} else {
Timber.i("Detected valid SSID")
}
}
}
private suspend fun settings(): Settings {
return if (autoTunnelStateFlow.value == defaultState) {
appDataRepository.get().settings.getSettings()
} else {
autoTunnelStateFlow.value.settings
}
}
@OptIn(FlowPreview::class) @OptIn(FlowPreview::class)
private fun startAutoTunnelJob() = lifecycleScope.launch(ioDispatcher) { private fun startAutoTunnelJob() = lifecycleScope.launch(ioDispatcher) {
Timber.i("Starting auto-tunnel network event watcher") Timber.i("Starting auto-tunnel network event watcher")

View File

@ -1,116 +0,0 @@
package com.zaneschepke.wireguardautotunnel.service.network
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.wifi.WifiManager
import android.os.Build
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import timber.log.Timber
abstract class BaseNetworkService<T : BaseNetworkService<T>>(
val context: Context,
networkCapability: Int,
) : NetworkService<T> {
private val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val wifiManager =
context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
private fun checkHasCapability(networkCapability: Int): Boolean {
val network = connectivityManager.activeNetwork
val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
return networkCapabilities?.hasTransport(networkCapability) == true
}
override val networkStatus =
callbackFlow {
val networkStatusCallback =
when (Build.VERSION.SDK_INT) {
in Build.VERSION_CODES.S..Int.MAX_VALUE -> {
object :
ConnectivityManager.NetworkCallback(
FLAG_INCLUDE_LOCATION_INFO,
) {
override fun onAvailable(network: Network) {
trySend(NetworkStatus.Available(network))
}
override fun onLost(network: Network) {
trySend(NetworkStatus.Unavailable())
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
trySend(
NetworkStatus.CapabilitiesChanged(
network,
networkCapabilities,
),
)
}
}
}
else -> {
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
trySend(NetworkStatus.Available(network))
}
override fun onLost(network: Network) {
trySend(NetworkStatus.Unavailable())
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
trySend(
NetworkStatus.CapabilitiesChanged(
network,
networkCapabilities,
),
)
}
}
}
}
val request =
NetworkRequest.Builder()
.addTransportType(networkCapability)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build()
connectivityManager.registerNetworkCallback(request, networkStatusCallback)
awaitClose { connectivityManager.unregisterNetworkCallback(networkStatusCallback) }
}.onStart {
// needed for services that are not yet available as it will impact later combine flows if we don't emit
emit(NetworkStatus.Unavailable())
}.catch {
Timber.e(it)
emit(NetworkStatus.Unavailable())
}
}
inline fun <Result> Flow<NetworkStatus>.map(
crossinline onUnavailable: suspend () -> Result,
crossinline onAvailable: suspend (network: Network) -> Result,
crossinline onCapabilitiesChanged:
suspend (network: Network, networkCapabilities: NetworkCapabilities) -> Result,
): Flow<Result> = map { status ->
when (status) {
is NetworkStatus.Unavailable -> onUnavailable()
is NetworkStatus.Available -> onAvailable(status.network)
is NetworkStatus.CapabilitiesChanged ->
onCapabilitiesChanged(
status.network,
status.networkCapabilities,
)
}
}

View File

@ -1,18 +1,64 @@
package com.zaneschepke.wireguardautotunnel.service.network package com.zaneschepke.wireguardautotunnel.service.network
import android.content.Context import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.NetworkRequest
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class EthernetService class EthernetService
@Inject @Inject
constructor( constructor(
@ApplicationContext context: Context, @ApplicationContext context: Context,
) : ) : NetworkService {
BaseNetworkService<EthernetService>(context, NetworkCapabilities.TRANSPORT_ETHERNET) {
override fun isNetworkSecure(): Boolean { private val connectivityManager =
return true context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
override val status = callbackFlow {
val networkStatusCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
trySend(NetworkStatus.Available(network))
}
override fun onLost(network: Network) {
trySend(NetworkStatus.Unavailable())
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
trySend(
NetworkStatus.CapabilitiesChanged(
network,
networkCapabilities,
),
)
}
}
val request =
NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build()
connectivityManager.registerNetworkCallback(request, networkStatusCallback)
awaitClose { connectivityManager.unregisterNetworkCallback(networkStatusCallback) }
}.onStart {
// needed for services that are not yet available as it will impact later combine flows if we don't emit
emit(NetworkStatus.Unavailable())
}.catch {
Timber.e(it)
emit(NetworkStatus.Unavailable())
}.map {
when (it) {
is NetworkStatus.Available, is NetworkStatus.CapabilitiesChanged -> Status(true, null)
is NetworkStatus.Unavailable -> Status(false, null)
}
} }
} }

View File

@ -1,17 +1,63 @@
package com.zaneschepke.wireguardautotunnel.service.network package com.zaneschepke.wireguardautotunnel.service.network
import android.content.Context import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.NetworkRequest
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class MobileDataService class MobileDataService
@Inject @Inject
constructor( constructor(
@ApplicationContext context: Context, @ApplicationContext context: Context,
) : ) : NetworkService {
BaseNetworkService<MobileDataService>(context, NetworkCapabilities.TRANSPORT_CELLULAR) { private val connectivityManager =
override fun isNetworkSecure(): Boolean { context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return false
override val status = callbackFlow {
val networkStatusCallback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
trySend(NetworkStatus.Available(network))
}
override fun onLost(network: Network) {
trySend(NetworkStatus.Unavailable())
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
trySend(
NetworkStatus.CapabilitiesChanged(
network,
networkCapabilities,
),
)
}
}
val request =
NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build()
connectivityManager.registerNetworkCallback(request, networkStatusCallback)
awaitClose { connectivityManager.unregisterNetworkCallback(networkStatusCallback) }
}.onStart {
// needed for services that are not yet available as it will impact later combine flows if we don't emit
emit(NetworkStatus.Unavailable())
}.catch {
Timber.e(it)
emit(NetworkStatus.Unavailable())
}.map {
when (it) {
is NetworkStatus.Available, is NetworkStatus.CapabilitiesChanged -> Status(true, null)
is NetworkStatus.Unavailable -> Status(false, null)
}
} }
} }

View File

@ -1,14 +1,27 @@
package com.zaneschepke.wireguardautotunnel.service.network package com.zaneschepke.wireguardautotunnel.service.network
import android.net.Network
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
interface NetworkService<T> { interface NetworkService {
fun getNetworkName(networkCapabilities: NetworkCapabilities): String? { val status: Flow<Status>
return null
} }
fun isNetworkSecure(): Boolean inline fun <Result> Flow<NetworkStatus>.map(
crossinline onUnavailable: suspend () -> Result,
val networkStatus: Flow<NetworkStatus> crossinline onAvailable: suspend (network: Network) -> Result,
crossinline onCapabilitiesChanged:
suspend (network: Network, networkCapabilities: NetworkCapabilities) -> Result,
): Flow<Result> = map { status ->
when (status) {
is NetworkStatus.Unavailable -> onUnavailable()
is NetworkStatus.Available -> onAvailable(status.network)
is NetworkStatus.CapabilitiesChanged ->
onCapabilitiesChanged(
status.network,
status.networkCapabilities,
)
}
} }

View File

@ -0,0 +1,6 @@
package com.zaneschepke.wireguardautotunnel.service.network
data class Status(
val available: Boolean,
val name: String?,
)

View File

@ -1,22 +1,134 @@
package com.zaneschepke.wireguardautotunnel.service.network package com.zaneschepke.wireguardautotunnel.service.network
import android.content.Context import android.content.Context
import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback.FLAG_INCLUDE_LOCATION_INFO
import android.net.Network
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.wifi.SupplicantState import android.net.wifi.SupplicantState
import android.net.wifi.WifiManager
import android.os.Build import android.os.Build
import com.wireguard.android.util.RootShell
import com.zaneschepke.wireguardautotunnel.data.repository.SettingsRepository
import com.zaneschepke.wireguardautotunnel.module.AppShell
import com.zaneschepke.wireguardautotunnel.util.extensions.getCurrentWifiName
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.transform
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Provider
class WifiService class WifiService
@Inject @Inject
constructor( constructor(
@ApplicationContext context: Context, @ApplicationContext private val context: Context,
) : private val settingsRepository: SettingsRepository,
BaseNetworkService<WifiService>(context, NetworkCapabilities.TRANSPORT_WIFI) { @AppShell private val rootShell: Provider<RootShell>
) : NetworkService {
override fun getNetworkName(networkCapabilities: NetworkCapabilities): String? { val mutex = Mutex()
private var ssid : String? = null
private var available : Boolean = false
private val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
override val status = callbackFlow {
val networkStatusCallback =
when (Build.VERSION.SDK_INT) {
in Build.VERSION_CODES.S..Int.MAX_VALUE -> {
object :
ConnectivityManager.NetworkCallback(
FLAG_INCLUDE_LOCATION_INFO,
) {
override fun onAvailable(network: Network) {
trySend(NetworkStatus.Available(network))
}
override fun onLost(network: Network) {
trySend(NetworkStatus.Unavailable())
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
trySend(
NetworkStatus.CapabilitiesChanged(
network,
networkCapabilities,
),
)
}
}
}
else -> {
object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
trySend(NetworkStatus.Available(network))
}
override fun onLost(network: Network) {
trySend(NetworkStatus.Unavailable())
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
trySend(
NetworkStatus.CapabilitiesChanged(
network,
networkCapabilities,
),
)
}
}
}
}
val request =
NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
.build()
connectivityManager.registerNetworkCallback(request, networkStatusCallback)
awaitClose { connectivityManager.unregisterNetworkCallback(networkStatusCallback) }
}.onStart {
// needed for services that are not yet available as it will impact later combine flows if we don't emit
emit(NetworkStatus.Unavailable())
}.catch {
Timber.e(it)
emit(NetworkStatus.Unavailable())
}.transform {
when(it) {
is NetworkStatus.Available -> mutex.withLock {
available = true
}
is NetworkStatus.CapabilitiesChanged -> mutex.withLock {
if(available) {
available = false
Timber.d("Getting SSID from capabilities")
ssid = getNetworkName(it.networkCapabilities)
}
emit(Status(true, ssid))
}
is NetworkStatus.Unavailable -> emit(Status(false, null))
}
}
private suspend fun getNetworkName(networkCapabilities: NetworkCapabilities): String? {
if(settingsRepository.getSettings().isWifiNameByShellEnabled) return rootShell.get().getCurrentWifiName()
var ssid = networkCapabilities.getWifiName() var ssid = networkCapabilities.getWifiName()
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S) {
val wifiManager =
context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
@Suppress("DEPRECATION")
val info = wifiManager.connectionInfo val info = wifiManager.connectionInfo
if (info.supplicantState === SupplicantState.COMPLETED) { if (info.supplicantState === SupplicantState.COMPLETED) {
ssid = info.ssid ssid = info.ssid
@ -24,9 +136,4 @@ constructor(
} }
return ssid?.trim('"') return ssid?.trim('"')
} }
override fun isNetworkSecure(): Boolean {
// TODO
return false
}
} }