fix: airplane mode detection

This commit is contained in:
zaneschepke
2026-05-26 06:07:35 -04:00
parent 82bda83464
commit 0963626164
@@ -24,7 +24,6 @@ import com.zaneschepke.networkmonitor.util.hasRequiredLocationPermissions
import com.zaneschepke.networkmonitor.util.isAirplaneModeOn import com.zaneschepke.networkmonitor.util.isAirplaneModeOn
import com.zaneschepke.networkmonitor.util.isLocationServicesEnabled import com.zaneschepke.networkmonitor.util.isLocationServicesEnabled
import java.net.Inet6Address import java.net.Inet6Address
import kotlin.concurrent.atomics.AtomicReference
import kotlin.concurrent.atomics.ExperimentalAtomicApi import kotlin.concurrent.atomics.ExperimentalAtomicApi
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@@ -455,8 +454,6 @@ class AndroidNetworkMonitor(
NetworkData(defaultEvent, wifiEvent, cellularEvent, ethernetEvent) NetworkData(defaultEvent, wifiEvent, cellularEvent, ethernetEvent)
} }
@OptIn(ExperimentalAtomicApi::class) private val vpnActiveState = AtomicReference(false)
@OptIn(ExperimentalCoroutinesApi::class, ExperimentalAtomicApi::class, FlowPreview::class) @OptIn(ExperimentalCoroutinesApi::class, ExperimentalAtomicApi::class, FlowPreview::class)
override val connectivityStateFlow: SharedFlow<ConnectivityState> = override val connectivityStateFlow: SharedFlow<ConnectivityState> =
combine( combine(
@@ -547,7 +544,8 @@ class AndroidNetworkMonitor(
} }
// only count cellular as connected if validated AND not in airplane mode // only count cellular as connected if validated AND not in airplane mode
networkData.cellularEvent is TransportEvent.CapabilitiesChanged && !isAirplaneOn &&
networkData.cellularEvent is TransportEvent.CapabilitiesChanged &&
networkData.cellularEvent.networkCapabilities?.let { caps -> networkData.cellularEvent.networkCapabilities?.let { caps ->
caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) && caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
caps.hasCapability( caps.hasCapability(
@@ -559,32 +557,20 @@ class AndroidNetworkMonitor(
caps.hasCapability( caps.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
) )
// NOT_SUSPENDED need to properly tell when we've lost mobile data } == true -> {
// connectivity
} == true &&
!isAirplaneOn -> {
ActiveNetwork.Cellular(networkData.cellularEvent.network) ActiveNetwork.Cellular(networkData.cellularEvent.network)
} }
else -> ActiveNetwork.Disconnected else -> ActiveNetwork.Disconnected
} }
val activeNetwork: ActiveNetwork = lastKnownActiveNetwork.value = physicalNetwork
if (!isVpnActive) {
physicalNetwork
} else {
lastKnownActiveNetwork.value
}
if (physicalNetwork != ActiveNetwork.Disconnected) {
lastKnownActiveNetwork.value = physicalNetwork
}
val underlyingNetwork: Network? = val underlyingNetwork: Network? =
when (val last = lastKnownActiveNetwork.value) { when (physicalNetwork) {
is ActiveNetwork.Wifi -> last.network is ActiveNetwork.Wifi -> physicalNetwork.network
is ActiveNetwork.Cellular -> last.network is ActiveNetwork.Cellular -> physicalNetwork.network
is ActiveNetwork.Ethernet -> last.network is ActiveNetwork.Ethernet -> physicalNetwork.network
else -> null else -> null
} }
@@ -602,13 +588,13 @@ class AndroidNetworkMonitor(
) )
ConnectivityState( ConnectivityState(
activeNetwork = activeNetwork, activeNetwork = physicalNetwork,
locationPermissionsGranted = permissions.locationPermissionGranted, locationPermissionsGranted = permissions.locationPermissionGranted,
locationServicesEnabled = permissions.locationServicesEnabled, locationServicesEnabled = permissions.locationServicesEnabled,
vpnState = vpnState, vpnState = vpnState,
effectiveDnsInfo = effectiveDns, effectiveDnsInfo = effectiveDns,
underlyingDnsInfo = underlyingDns, underlyingDnsInfo = underlyingDns,
hasIpv6 = hasIpv6Support(underlyingNetwork, activeNetwork), hasIpv6 = hasIpv6Support(underlyingNetwork, physicalNetwork),
) )
} }
.distinctUntilChanged() .distinctUntilChanged()
@@ -694,11 +680,13 @@ class AndroidNetworkMonitor(
object : BroadcastReceiver() { object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_AIRPLANE_MODE_CHANGED) { if (intent.action == Intent.ACTION_AIRPLANE_MODE_CHANGED) {
Timber.d("Received airplane mode changed broadcast") val isAirplaneOn = intent.getBooleanExtra("state", false)
airplaneModeState.update { appContext.isAirplaneModeOn() } Timber.d("Airplane mode changed to new state: $isAirplaneOn")
airplaneModeState.update { isAirplaneOn }
} }
} }
} }
appContext.registerReceiver( appContext.registerReceiver(
airplaneReceiver, airplaneReceiver,
IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED), IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED),