Skip to content

Commit

Permalink
fix(android): try async state fetch as stale state workaround (#547)
Browse files Browse the repository at this point in the history
* Test a possible fix for #542
For review.
* Combine 6.2.0 and 6.2.1 fixes into one.

Co-authored-by: Cristiano Coelho <cristianocca@hotmail.com>
  • Loading branch information
cristianoccazinsp and cristianocca committed Dec 7, 2021
1 parent 0126a26 commit 937cf48
Showing 1 changed file with 52 additions and 17 deletions.
Expand Up @@ -15,6 +15,8 @@
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;

import com.facebook.react.bridge.ReactApplicationContext;
import com.reactnativecommunity.netinfo.types.CellularGeneration;
Expand All @@ -27,8 +29,21 @@
*/
@TargetApi(Build.VERSION_CODES.N)
public class NetworkCallbackConnectivityReceiver extends ConnectivityReceiver {
private static final int DELAY_MS = 250;
private final ConnectivityNetworkCallback mNetworkCallback;

// from the docs:
// "Do NOT call ConnectivityManager.getNetworkCapabilities(android.net.Network)
// or ConnectivityManager.getLinkProperties(android.net.Network) or other
// synchronous ConnectivityManager methods in this callback as this is
// prone to race conditions ; calling these methods while in a callback
// may return an outdated or even a null object."
// https://developer.android.com/reference/android/net/ConnectivityManager.NetworkCallback
// For this reason, we will fetch these values when not provided by the callback
// on an asynchronous thread.
private Network mNetwork = null;
private NetworkCapabilities mCapabilities = null;

public NetworkCallbackConnectivityReceiver(ReactApplicationContext reactContext) {
super(reactContext);
mNetworkCallback = new ConnectivityNetworkCallback();
Expand Down Expand Up @@ -58,39 +73,37 @@ public void unregister() {

@SuppressLint("MissingPermission")
void updateAndSend() {
Network network = getConnectivityManager().getActiveNetwork();
NetworkCapabilities capabilities = getConnectivityManager().getNetworkCapabilities(network);
ConnectionType connectionType = ConnectionType.UNKNOWN;
CellularGeneration cellularGeneration = null;
NetworkInfo networkInfo = null;
boolean isInternetReachable = false;
boolean isInternetSuspended = false;

if (capabilities != null) {
if (mCapabilities != null) {
// Get the connection type
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
if (mCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH)) {
connectionType = ConnectionType.BLUETOOTH;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
} else if (mCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
connectionType = ConnectionType.CELLULAR;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
} else if (mCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
connectionType = ConnectionType.ETHERNET;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
} else if (mCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
connectionType = ConnectionType.WIFI;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
} else if (mCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
connectionType = ConnectionType.VPN;
}

if (network != null) {
if (mNetwork != null) {
// This may return null per API docs, and is deprecated, but for older APIs (< VERSION_CODES.P)
// we need it to test for suspended internet
networkInfo = getConnectivityManager().getNetworkInfo(network);
networkInfo = getConnectivityManager().getNetworkInfo(mNetwork);
}

// Check to see if the network is temporarily unavailable or if airplane mode is toggled on
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
isInternetSuspended = !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
isInternetSuspended = !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
} else {
if (network != null && networkInfo != null) {
if (mNetwork != null && networkInfo != null) {
NetworkInfo.DetailedState detailedConnectionState = networkInfo.getDetailedState();
if (!detailedConnectionState.equals(NetworkInfo.DetailedState.CONNECTED)) {
isInternetSuspended = true;
Expand All @@ -99,13 +112,13 @@ void updateAndSend() {
}

isInternetReachable =
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& capabilities.hasCapability(
mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
&& mCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_VALIDATED)
&& !isInternetSuspended;

// Get the cellular network type
if (network != null && connectionType == ConnectionType.CELLULAR && isInternetReachable) {
if (mNetwork != null && connectionType == ConnectionType.CELLULAR && isInternetReachable) {
cellularGeneration = CellularGeneration.fromNetworkInfo(networkInfo);
}
} else {
Expand All @@ -115,36 +128,58 @@ void updateAndSend() {
updateConnectivity(connectionType, cellularGeneration, isInternetReachable);
}

private void asyncUpdateAndSend() {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
mCapabilities = getConnectivityManager().getNetworkCapabilities(mNetwork);
updateAndSend();

}
}, DELAY_MS);
}

private class ConnectivityNetworkCallback extends ConnectivityManager.NetworkCallback {
@Override
public void onAvailable(Network network) {
updateAndSend();
mNetwork = network;
asyncUpdateAndSend();
}

@Override
public void onLosing(Network network, int maxMsToLive) {
mNetwork = network;
updateAndSend();
}

@Override
public void onLost(Network network) {
mNetwork = null;
mCapabilities = null;
updateAndSend();
}

@Override
public void onUnavailable() {
mNetwork = null;
mCapabilities = null;
updateAndSend();
}

@Override
public void onCapabilitiesChanged(
Network network, NetworkCapabilities networkCapabilities) {
mNetwork = network;
mCapabilities = networkCapabilities;
updateAndSend();
}

@Override
public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
updateAndSend();
if (mNetwork != null) {
mNetwork = network;
}
asyncUpdateAndSend();
}
}
}

0 comments on commit 937cf48

Please sign in to comment.