This commit is contained in:
4 files changed
+349
-11
No files matched your search
@@ -3,6 +3,9 @@ package com.m57.hermescontrol.data.remote
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Network
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Build
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
@@ -19,6 +22,10 @@ object NetworkMonitor {
|
||||
private val networkChangeEvents = MutableSharedFlow<Boolean>(extraBufferCapacity = Int.MAX_VALUE)
|
||||
internal val networkChanges: SharedFlow<Boolean> = networkChangeEvents.asSharedFlow()
|
||||
|
||||
// Emitted when default network transports change without onLost/onAvailable (issue #1165).
|
||||
private val transportChangeEvents = MutableSharedFlow<Unit>(extraBufferCapacity = Int.MAX_VALUE)
|
||||
internal val transportChanges: SharedFlow<Unit> = transportChangeEvents.asSharedFlow()
|
||||
|
||||
private val callbackLock = Any()
|
||||
private val callbackGeneration = AtomicInteger(0)
|
||||
private var callbackRegistration: Pair<ConnectivityManager, ConnectivityManager.NetworkCallback>? = null
|
||||
@@ -26,6 +33,9 @@ object NetworkMonitor {
|
||||
@Volatile
|
||||
private var defaultNetwork: Network? = null
|
||||
|
||||
@Volatile
|
||||
private var currentTransports: Set<Int>? = null
|
||||
|
||||
fun init(context: Context) {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val callback = createCallback(cm)
|
||||
@@ -38,6 +48,10 @@ object NetworkMonitor {
|
||||
defaultNetwork = activeNetwork
|
||||
networkAvailable = activeNetwork != null
|
||||
_isConnected.value = networkAvailable
|
||||
currentTransports =
|
||||
runCatching {
|
||||
activeNetwork?.let { cm.getNetworkCapabilities(it) }?.let { extractTransports(it) }
|
||||
}.getOrNull()
|
||||
callbackRegistration.also { callbackRegistration = cm to callback }
|
||||
}
|
||||
if (networkChanged) networkChangeEvents.tryEmit(networkAvailable)
|
||||
@@ -56,6 +70,7 @@ object NetworkMonitor {
|
||||
if (callbackGeneration.get() != generation) return
|
||||
(defaultNetwork != network).also {
|
||||
defaultNetwork = network
|
||||
currentTransports = null
|
||||
_isConnected.value = true
|
||||
}
|
||||
}
|
||||
@@ -71,11 +86,86 @@ object NetworkMonitor {
|
||||
(defaultNetwork != activeNetwork).also {
|
||||
defaultNetwork = activeNetwork
|
||||
networkAvailable = activeNetwork != null
|
||||
currentTransports = null
|
||||
_isConnected.value = networkAvailable
|
||||
}
|
||||
}
|
||||
if (changed) networkChangeEvents.tryEmit(networkAvailable)
|
||||
}
|
||||
|
||||
override fun onCapabilitiesChanged(
|
||||
network: Network,
|
||||
networkCapabilities: NetworkCapabilities,
|
||||
) {
|
||||
val transportChanged: Boolean
|
||||
synchronized(callbackLock) {
|
||||
if (callbackGeneration.get() != generation || defaultNetwork != network) return
|
||||
val newTransports = extractTransports(networkCapabilities)
|
||||
val oldTransports = currentTransports
|
||||
currentTransports = newTransports
|
||||
transportChanged = oldTransports != null && oldTransports != newTransports
|
||||
}
|
||||
if (transportChanged) {
|
||||
transportChangeEvents.tryEmit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLosing(
|
||||
network: Network,
|
||||
maxMsToLive: Int,
|
||||
) {
|
||||
val isDefault: Boolean
|
||||
synchronized(callbackLock) {
|
||||
if (callbackGeneration.get() != generation || defaultNetwork != network) return
|
||||
isDefault = true
|
||||
}
|
||||
if (isDefault) {
|
||||
transportChangeEvents.tryEmit(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun extractTransports(capabilities: NetworkCapabilities?): Set<Int> {
|
||||
if (capabilities == null) return emptySet()
|
||||
val transports = mutableSetOf<Int>()
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
transports.add(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
}
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||
transports.add(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
}
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
|
||||
transports.add(NetworkCapabilities.TRANSPORT_BLUETOOTH)
|
||||
}
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
|
||||
transports.add(NetworkCapabilities.TRANSPORT_ETHERNET)
|
||||
}
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
||||
transports.add(NetworkCapabilities.TRANSPORT_VPN)
|
||||
}
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
|
||||
transports.add(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 &&
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_LOWPAN)
|
||||
) {
|
||||
transports.add(NetworkCapabilities.TRANSPORT_LOWPAN)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
|
||||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_USB)
|
||||
) {
|
||||
transports.add(NetworkCapabilities.TRANSPORT_USB)
|
||||
}
|
||||
return transports
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun resetForTest() {
|
||||
synchronized(callbackLock) {
|
||||
defaultNetwork = null
|
||||
currentTransports = null
|
||||
_isConnected.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user