Callback for ConnectivityManager not working in BlueStacks 5 emulator

169 Views Asked by At

In order to get notified when the device connects/disconnects from internet, I took the following approach:

        ConnectivityManager connectivityManager = activity.getSystemService(ConnectivityManager.class);

        ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(@NonNull Network network) {
                super.onAvailable(network);
                try {
                    activity.runOnUiThread(() -> {
                        tvNoInternet.animate().alpha(0f).setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                super.onAnimationEnd(animation);
                                MiscellaneousUtils.hideView(tvNoInternet, View.GONE);
                            }
                        });
                        behaviour.onConnected();
                        // behaviour is an interface named NetworkConnectionBehaviour (check the following snippet for its implementation)
                    });
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onLost(@NonNull Network network) {
                super.onLost(network);
                try {
                    activity.runOnUiThread(() -> {
                        if (isInternetConnected(activity)) {
                            // check internet connection status because onLost() is called
                            // after onAvailable() when the device automatically switches
                            // internet connection from cellular to wifi
                            return;
                        }
                        tvNoInternet.animate().alpha(1f).setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationStart(Animator animation) {
                                super.onAnimationStart(animation);
                                MiscellaneousUtils.showView(tvNoInternet);
                            }
                        });
                        behaviour.onDisconnected();
                    });
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                }
            }
        };

        try {
            NetworkRequest networkRequest = getNetworkRequest(); 
            // implementation of getNetworkRequest() is added in next snippet
            connectivityManager.registerNetworkCallback(networkRequest, networkCallback);
        } catch (Exception e) {
            Toast.makeText(activity, "Unexpected interruption! please try again later", Toast.LENGTH_SHORT).show();
        }

Interface NetowrkConnectionBehaviour:

    public interface NetworkConnectionBehaviour {
        void onConnected();

        void onDisconnected();
    }

Implementation of getNetworkRequest():

    public static NetworkRequest getNetworkRequest() {
        return new NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                .build();
    }

This approach is working in all physical devices and emulator of android studio.

However, if someone runs the app on Bluestacks 5 emulator, the callbacks of ConnectivityManager aren't called at all. And it does not produce any exception either.

Am I missing something here? Is there a different way to use ConnectivityManager for BlueStacks?

NOTE: It shows same behaviour for gameloop emulator too.

2

There are 2 best solutions below

0
sweak On BEST ANSWER

The solution is to remove transport types: TRANSPORT_WIFI and TRANSPORT_CELLULAR since the BlueStacks 5 Emulator does not recognize its connection to be one of those transport types.

The capability NET_CAPABILITY_INTERNET will ensure that the connection is working and has access to the internet as per docs:

Indicates that this network should be able to reach the internet.

The code for the NetworkRequest now should be as follows:

public static NetworkRequest getNetworkRequest() {
    return new NetworkRequest.Builder()
        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
        .build();
}
0
eunwoo On

In order to get notified when the device connects/disconnects from internet, It's better to use registerDefaultNetworkCallback instead of just registerNetworkCallback. The "default network" means application's default network used for internet connection. as per docs. https://developer.android.com/reference/android/net/ConnectivityManager

Try

connectivityManager.registerDefaultNetworkCallback(networkCallback);

And you can use callback as you defined in the question.

AND also, if you want to check it's connected, you should check both NET_CAPABILITY_INTERNET AND NET_CAPABILITY_VALIDATED. So I used connectivity check like below.

val caps = mConnectivityManager.getNetworkCapabilities(network)
if (caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
            caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
    // connected
}