Skip to content

Instantly share code, notes, and snippets.

@dylangrijalva
Last active March 20, 2025 21:17
Show Gist options
  • Select an option

  • Save dylangrijalva/cb289de4e28dc8b6fdd11b9d84e56cd9 to your computer and use it in GitHub Desktop.

Select an option

Save dylangrijalva/cb289de4e28dc8b6fdd11b9d84e56cd9 to your computer and use it in GitHub Desktop.
Helper classes to get the network state using built-in android APIs.
class AndroidNetworkModule(
private val context: Context,
private val dispatchers: CoroutineDispatchers,
) : NetworkModule {
private val connectivityManager: ConnectivityManager
get() = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
override fun stream(): Flow<NetworkState> {
return callbackFlow {
val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
val networkState = getNetworkState()
trySend(networkState)
}
override fun onLost(network: Network) {
val networkState = getNetworkState()
trySend(networkState)
}
}
val request = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(request, callback)
val networkState = getNetworkState()
trySend(networkState)
awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
}.flowOn(dispatchers.computation)
}
override fun getNetworkState(): NetworkState {
try {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
val netInfo = connectivityManager.activeNetworkInfo
?: return NetworkState(
isConnected = false,
isInternetReachable = false,
type = NetworkStateType.UNKNOWN
)
val connectionType = getConnectionType(netInfo)
return NetworkState(
isConnected = connectionType.isDefined,
isInternetReachable = netInfo.isConnected,
type = connectionType
)
} else {
val network = connectivityManager.activeNetwork
val isInternetReachable = network != null
val connectionType = if (isInternetReachable) {
val netCapabilities = connectivityManager.getNetworkCapabilities(network)
getConnectionType(netCapabilities)
} else {
null
}
return NetworkState(
isConnected = connectionType != null && connectionType.isDefined,
isInternetReachable = isInternetReachable,
type = connectionType ?: NetworkStateType.UNKNOWN
)
}
} catch (e: Exception) {
throw Exception("Unable to access network information", e.cause)
}
}
private fun getConnectionType(netInfo: NetworkInfo?): NetworkStateType {
return when (netInfo?.type) {
TYPE_MOBILE,
TYPE_MOBILE_DUN -> NetworkStateType.CELLULAR
TYPE_WIFI -> NetworkStateType.WIFI
TYPE_BLUETOOTH -> NetworkStateType.BLUETOOTH
TYPE_ETHERNET -> NetworkStateType.ETHERNET
TYPE_WIMAX -> NetworkStateType.WIMAX
TYPE_VPN -> NetworkStateType.VPN
else -> NetworkStateType.UNKNOWN
}
}
private fun getConnectionType(netCapabilities: NetworkCapabilities?): NetworkStateType =
when {
netCapabilities == null -> NetworkStateType.UNKNOWN
netCapabilities.hasTransport(TRANSPORT_CELLULAR) -> NetworkStateType.CELLULAR
netCapabilities.hasTransport(TRANSPORT_WIFI) || netCapabilities.hasTransport(TRANSPORT_WIFI_AWARE) -> NetworkStateType.WIFI
netCapabilities.hasTransport(TRANSPORT_BLUETOOTH) -> NetworkStateType.BLUETOOTH
netCapabilities.hasTransport(TRANSPORT_ETHERNET) -> NetworkStateType.ETHERNET
netCapabilities.hasTransport(TRANSPORT_VPN) -> NetworkStateType.VPN
else -> NetworkStateType.UNKNOWN
}
}
data class NetworkState(
val isConnected: Boolean,
val isInternetReachable: Boolean,
val type: NetworkStateType
)
enum class NetworkStateType(val value: String) {
NONE("NONE"),
UNKNOWN("UNKNOWN"),
CELLULAR("CELLULAR"),
WIFI("WIFI"),
BLUETOOTH("BLUETOOTH"),
ETHERNET("ETHERNET"),
WIMAX("WIMAX"),
VPN("VPN"),
OTHER("OTHER");
val isDefined: Boolean
get() = this.value != "NONE" && this.value != "UNKNOWN"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment