parent
fe45a2fad9
commit
25b986ef2f
|
@ -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
|
|
@ -13,15 +13,19 @@ import dagger.hilt.android.scopes.ServiceScoped
|
|||
@Module
|
||||
@InstallIn(ServiceComponent::class)
|
||||
abstract class ServiceModule {
|
||||
@Binds
|
||||
@ServiceScoped
|
||||
abstract fun provideWifiService(wifiService: WifiService): NetworkService<WifiService>
|
||||
|
||||
@Binds
|
||||
@Wifi
|
||||
@ServiceScoped
|
||||
abstract fun provideMobileDataService(mobileDataService: MobileDataService): NetworkService<MobileDataService>
|
||||
abstract fun provideWifiService(wifiService: WifiService): NetworkService
|
||||
|
||||
@Binds
|
||||
@MobileData
|
||||
@ServiceScoped
|
||||
abstract fun provideEthernetService(ethernetService: EthernetService): NetworkService<EthernetService>
|
||||
abstract fun provideMobileDataService(mobileDataService: MobileDataService): NetworkService
|
||||
|
||||
@Binds
|
||||
@Ethernet
|
||||
@ServiceScoped
|
||||
abstract fun provideEthernetService(ethernetService: EthernetService): NetworkService
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
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.repository.AppDataRepository
|
||||
import com.zaneschepke.wireguardautotunnel.module.AppShell
|
||||
import com.zaneschepke.wireguardautotunnel.module.Ethernet
|
||||
import com.zaneschepke.wireguardautotunnel.module.IoDispatcher
|
||||
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.autotunnel.model.AutoTunnelEvent
|
||||
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelState
|
||||
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.NetworkStatus
|
||||
import com.zaneschepke.wireguardautotunnel.service.network.WifiService
|
||||
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationAction
|
||||
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
|
||||
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.extensions.TunnelConfigs
|
||||
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.onNotRunning
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
@ -64,13 +61,16 @@ class AutoTunnelService : LifecycleService() {
|
|||
lateinit var rootShell: Provider<RootShell>
|
||||
|
||||
@Inject
|
||||
lateinit var wifiService: NetworkService<WifiService>
|
||||
@Wifi
|
||||
lateinit var wifiService: NetworkService
|
||||
|
||||
@Inject
|
||||
lateinit var mobileDataService: NetworkService<MobileDataService>
|
||||
@MobileData
|
||||
lateinit var mobileDataService: NetworkService
|
||||
|
||||
@Inject
|
||||
lateinit var ethernetService: NetworkService<EthernetService>
|
||||
@Ethernet
|
||||
lateinit var ethernetService: NetworkService
|
||||
|
||||
@Inject
|
||||
lateinit var appDataRepository: Provider<AppDataRepository>
|
||||
|
@ -242,6 +242,7 @@ class AutoTunnelService : LifecycleService() {
|
|||
) { double, networkState ->
|
||||
AutoTunnelState(tunnelService.get().vpnState.value, networkState, double.first, double.second)
|
||||
}.collect { state ->
|
||||
Timber.d("Network state: ${state.networkState}")
|
||||
autoTunnelStateFlow.update {
|
||||
it.copy(vpnState = state.vpnState, networkState = state.networkState, settings = state.settings, tunnels = state.tunnels)
|
||||
}
|
||||
|
@ -256,19 +257,14 @@ class AutoTunnelService : LifecycleService() {
|
|||
@OptIn(FlowPreview::class)
|
||||
private fun combineNetworkEventsJob(): Flow<NetworkState> {
|
||||
return combine(
|
||||
wifiService.networkStatus,
|
||||
mobileDataService.networkStatus,
|
||||
ethernetService.networkStatus,
|
||||
) { wifi, mobileData, ethernet ->
|
||||
wifiService.status,
|
||||
mobileDataService.status,
|
||||
) { wifi, mobileData ->
|
||||
NetworkState(
|
||||
wifi.isConnected,
|
||||
mobileData.isConnected,
|
||||
ethernet.isConnected,
|
||||
when (wifi) {
|
||||
is NetworkStatus.CapabilitiesChanged -> getWifiSSID(wifi.networkCapabilities)
|
||||
is NetworkStatus.Available -> autoTunnelStateFlow.value.networkState.wifiName
|
||||
is NetworkStatus.Unavailable -> null
|
||||
},
|
||||
wifi.available,
|
||||
mobileData.available,
|
||||
false,
|
||||
wifi.name
|
||||
)
|
||||
}.distinctUntilChanged().filterNot { it.isWifiConnected && it.wifiName == null }.debounce(500L)
|
||||
}
|
||||
|
@ -285,28 +281,6 @@ class AutoTunnelService : LifecycleService() {
|
|||
}.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)
|
||||
private fun startAutoTunnelJob() = lifecycleScope.launch(ioDispatcher) {
|
||||
Timber.i("Starting auto-tunnel network event watcher")
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,18 +1,64 @@
|
|||
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 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
|
||||
|
||||
class EthernetService
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext context: Context,
|
||||
) :
|
||||
BaseNetworkService<EthernetService>(context, NetworkCapabilities.TRANSPORT_ETHERNET) {
|
||||
) : NetworkService {
|
||||
|
||||
override fun isNetworkSecure(): Boolean {
|
||||
return true
|
||||
private val connectivityManager =
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,63 @@
|
|||
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 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
|
||||
|
||||
class MobileDataService
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext context: Context,
|
||||
) :
|
||||
BaseNetworkService<MobileDataService>(context, NetworkCapabilities.TRANSPORT_CELLULAR) {
|
||||
override fun isNetworkSecure(): Boolean {
|
||||
return false
|
||||
) : NetworkService {
|
||||
private val connectivityManager =
|
||||
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_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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,27 @@
|
|||
package com.zaneschepke.wireguardautotunnel.service.network
|
||||
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
interface NetworkService<T> {
|
||||
fun getNetworkName(networkCapabilities: NetworkCapabilities): String? {
|
||||
return null
|
||||
}
|
||||
|
||||
fun isNetworkSecure(): Boolean
|
||||
|
||||
val networkStatus: Flow<NetworkStatus>
|
||||
interface NetworkService {
|
||||
val status: Flow<Status>
|
||||
}
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package com.zaneschepke.wireguardautotunnel.service.network
|
||||
|
||||
data class Status(
|
||||
val available: Boolean,
|
||||
val name: String?,
|
||||
)
|
|
@ -1,22 +1,134 @@
|
|||
package com.zaneschepke.wireguardautotunnel.service.network
|
||||
|
||||
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.NetworkRequest
|
||||
import android.net.wifi.SupplicantState
|
||||
import android.net.wifi.WifiManager
|
||||
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 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.Provider
|
||||
|
||||
class WifiService
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext context: Context,
|
||||
) :
|
||||
BaseNetworkService<WifiService>(context, NetworkCapabilities.TRANSPORT_WIFI) {
|
||||
@ApplicationContext private val context: Context,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
@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()
|
||||
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
|
||||
if (info.supplicantState === SupplicantState.COMPLETED) {
|
||||
ssid = info.ssid
|
||||
|
@ -24,9 +136,4 @@ constructor(
|
|||
}
|
||||
return ssid?.trim('"')
|
||||
}
|
||||
|
||||
override fun isNetworkSecure(): Boolean {
|
||||
// TODO
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue