From 3765df9c39411145418af97b92b646519ba28325 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 27 Jun 2023 17:58:45 +0200 Subject: [PATCH] NetworkMonitor: new strategy, looks like it works. --- .../networkmonitor/impl/NetworkMonitorImpl.kt | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/NetworkMonitorImpl.kt b/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/NetworkMonitorImpl.kt index 3901ec4120..ce881163f1 100644 --- a/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/NetworkMonitorImpl.kt +++ b/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/NetworkMonitorImpl.kt @@ -38,8 +38,10 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import timber.log.Timber +import java.util.concurrent.atomic.AtomicInteger import javax.inject.Inject @ContributesBinding(scope = AppScope::class) @@ -54,27 +56,31 @@ class NetworkMonitorImpl @Inject constructor( override val connectivity: StateFlow = callbackFlow { /** - * Assume there is no network available as soon as onLost is called. - * Reading activeNetwork synchronously from the callback is not safe. - * If there is an other active network we'll get some callback in onCapabilitiesChanged. + * Calling connectivityManager methods synchronously from the callbacks is not safe. + * So instead we just keep the count of active networks, ie. those checking the capability request. * Debounce the result to avoid quick offline<->online changes. */ val callback = object : ConnectivityManager.NetworkCallback() { + + private val activeNetworksCount = AtomicInteger(0) + override fun onLost(network: Network) { - trySendBlocking(NetworkStatus.Offline) + if (activeNetworksCount.decrementAndGet() == 0) { + trySendBlocking(NetworkStatus.Offline) + } } - override fun onCapabilitiesChanged( - network: Network, - networkCapabilities: NetworkCapabilities - ) { - trySendBlocking(networkCapabilities.getNetworkStatus()) + override fun onAvailable(network: Network) { + if (activeNetworksCount.incrementAndGet() > 0) { + trySendBlocking(NetworkStatus.Online) + } } } trySendBlocking(connectivityManager.activeNetworkStatus()) val request = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) .build() + connectivityManager.registerNetworkCallback(request, callback) Timber.d("Subscribe") awaitClose { @@ -84,6 +90,9 @@ class NetworkMonitorImpl @Inject constructor( } .distinctUntilChanged() .debounce(300) + .onEach { + Timber.d("NetworkStatus changed=$it") + } .stateIn(appCoroutineScope, SharingStarted.WhileSubscribed(), connectivityManager.activeNetworkStatus()) private fun ConnectivityManager.activeNetworkStatus(): NetworkStatus {