|
|
@ -26,57 +26,68 @@ import android.net.NetworkRequest.Builder
|
|
|
|
import android.os.Build.VERSION
|
|
|
|
import android.os.Build.VERSION
|
|
|
|
import android.os.Build.VERSION_CODES
|
|
|
|
import android.os.Build.VERSION_CODES
|
|
|
|
import androidx.core.content.getSystemService
|
|
|
|
import androidx.core.content.getSystemService
|
|
|
|
|
|
|
|
import androidx.tracing.trace
|
|
|
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.network.Dispatcher
|
|
|
|
|
|
|
|
import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO
|
|
|
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
|
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
|
|
|
|
|
|
import kotlinx.coroutines.CoroutineDispatcher
|
|
|
|
import kotlinx.coroutines.channels.awaitClose
|
|
|
|
import kotlinx.coroutines.channels.awaitClose
|
|
|
|
import kotlinx.coroutines.flow.Flow
|
|
|
|
import kotlinx.coroutines.flow.Flow
|
|
|
|
import kotlinx.coroutines.flow.callbackFlow
|
|
|
|
import kotlinx.coroutines.flow.callbackFlow
|
|
|
|
import kotlinx.coroutines.flow.conflate
|
|
|
|
import kotlinx.coroutines.flow.conflate
|
|
|
|
|
|
|
|
import kotlinx.coroutines.flow.flowOn
|
|
|
|
import javax.inject.Inject
|
|
|
|
import javax.inject.Inject
|
|
|
|
|
|
|
|
|
|
|
|
internal class ConnectivityManagerNetworkMonitor @Inject constructor(
|
|
|
|
internal class ConnectivityManagerNetworkMonitor @Inject constructor(
|
|
|
|
@ApplicationContext private val context: Context,
|
|
|
|
@ApplicationContext private val context: Context,
|
|
|
|
|
|
|
|
@Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher,
|
|
|
|
) : NetworkMonitor {
|
|
|
|
) : NetworkMonitor {
|
|
|
|
override val isOnline: Flow<Boolean> = callbackFlow {
|
|
|
|
override val isOnline: Flow<Boolean> = callbackFlow {
|
|
|
|
val connectivityManager = context.getSystemService<ConnectivityManager>()
|
|
|
|
trace("NetworkMonitor.callbackFlow") {
|
|
|
|
if (connectivityManager == null) {
|
|
|
|
val connectivityManager = context.getSystemService<ConnectivityManager>()
|
|
|
|
channel.trySend(false)
|
|
|
|
if (connectivityManager == null) {
|
|
|
|
channel.close()
|
|
|
|
channel.trySend(false)
|
|
|
|
return@callbackFlow
|
|
|
|
channel.close()
|
|
|
|
}
|
|
|
|
return@callbackFlow
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* The callback's methods are invoked on changes to *any* network matching the [NetworkRequest],
|
|
|
|
* 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].
|
|
|
|
* not just the active network. So we can simply track the presence (or absence) of such [Network].
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
val callback = object : NetworkCallback() {
|
|
|
|
val callback = object : NetworkCallback() {
|
|
|
|
|
|
|
|
|
|
|
|
private val networks = mutableSetOf<Network>()
|
|
|
|
private val networks = mutableSetOf<Network>()
|
|
|
|
|
|
|
|
|
|
|
|
override fun onAvailable(network: Network) {
|
|
|
|
override fun onAvailable(network: Network) {
|
|
|
|
networks += network
|
|
|
|
networks += network
|
|
|
|
channel.trySend(true)
|
|
|
|
channel.trySend(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
override fun onLost(network: Network) {
|
|
|
|
override fun onLost(network: Network) {
|
|
|
|
networks -= network
|
|
|
|
networks -= network
|
|
|
|
channel.trySend(networks.isNotEmpty())
|
|
|
|
channel.trySend(networks.isNotEmpty())
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val request = Builder()
|
|
|
|
trace("NetworkMonitor.registerNetworkCallback") {
|
|
|
|
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
|
|
|
val request = Builder()
|
|
|
|
.build()
|
|
|
|
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
|
|
|
connectivityManager.registerNetworkCallback(request, callback)
|
|
|
|
.build()
|
|
|
|
|
|
|
|
connectivityManager.registerNetworkCallback(request, callback)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Sends the latest connectivity status to the underlying channel.
|
|
|
|
* Sends the latest connectivity status to the underlying channel.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
channel.trySend(connectivityManager.isCurrentlyConnected())
|
|
|
|
channel.trySend(connectivityManager.isCurrentlyConnected())
|
|
|
|
|
|
|
|
|
|
|
|
awaitClose {
|
|
|
|
awaitClose {
|
|
|
|
connectivityManager.unregisterNetworkCallback(callback)
|
|
|
|
connectivityManager.unregisterNetworkCallback(callback)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.flowOn(ioDispatcher)
|
|
|
|
.conflate()
|
|
|
|
.conflate()
|
|
|
|
|
|
|
|
|
|
|
|
@Suppress("DEPRECATION")
|
|
|
|
@Suppress("DEPRECATION")
|
|
|
|