android / android/nowinandroid

[Bug]: ConnectivityManagerNetworkMonitor: onBlockedStatusChanged(...)

Open
#904 4 comments 1 reaction 0 assignees View on GitHub
bug
Dominant language
Kotlin
Stars
21.8k
Forks
4.6k
Avg merge
19h 20m
Merged PRs (30d)
2

Description

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Is there a StackOverflow question about this issue?

- [X] I have searched StackOverflow

### What happened?

When an app goes to the background, onBlockedStatusChanged is called with true and then called with false when it comes back to the foreground. The function onAvailable isn't called in this case.

When blocked = true, The app cannot access the network;
When blocked = false, The app can access the network.

In this scenario, NetworkMonitor.isOnline is not changed!

code :

`
class ConnectivityManagerNetworkMonitor @Inject constructor(
@ApplicationContext private val context: Context,
) : NetworkMonitor {
override val isOnline: Flow = callbackFlow {
val connectivityManager = context.getSystemService()
if (connectivityManager == null) {
channel.trySend(false)
channel.close()
return@callbackFlow
}

/**
* The callback's methods are invoked on changes to *any* network matching the [NetworkRequest],
* not just the active network. So we can simply track the presence (or absence) of such [Network].
*/
val callback = object : NetworkCallback() {

private val networks = mutableSetOf()

override fun onAvailable(network: Network) {
networks += network
channel.trySend(true)
Timber.i("onAvailable:${networks.isNotEmpty()}")
}

override fun onLost(network: Network) {
networks -= network
channel.trySend(networks.isNotEmpty())
Timber.i("onLost:${networks.isNotEmpty()}")
}

override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
Timber.i("onCapabilitiesChanged:${network}, ${networkCapabilities.toString()}")
}

override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
Timber.i("onCapabilitiesChanged:${network}, blocked = $blocked")
}
}

val request = Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(request, callback)

/**
* Sends the latest connectivity status to the underlying channel.
*/
channel.trySend(connectivityManager.isCurrentlyConnected())

awaitClose {
connectivityManager.unregisterNetworkCallback(callback)
}
}
.conflate()
}

`

### Relevant logcat output

_No response_

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct

Contributor guide

Open the contributing guide

Research direction

Start with the ConnectivityManagerNetworkMonitor implementation shown in the issue and trace how its callbackFlow updates isOnline during the background/foreground transition. Reproduce the onBlockedStatusChanged(true) and onBlockedStatusChanged(false) sequence, then verify that isOnline reflects the app's actual network access when the transition is complete.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile, networking
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.