How to Check Internet Connection in Android Programmatically?

How to Check Internet Connection in Android

Today, you will learn how to check the internet connection in Android. We will also see how to test if the connected network has access to the internet. If you don’t want to read the explanation, jump to the final code.

For this article, create a method called isDeviceOnline() in your MainActivity. If the user is online, it returns true; otherwise, it returns false. It also takes the Context parameter.

fun isDeviceOnline(context: Context): Boolean {

}

Add the following permissions in the Manifest file:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

In Android, we can get the state of the network by using the ConnectivityManager API. We can get its object from the getSystemService() method.

val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager

To check if the device is online, call the getNetworkCapabilities() method. It looks like this:

public NetworkCapabilities getNetworkCapabilities (Network network)

It takes the Network object. We can get it from the getActiveNetwork() method of ConnectivityManager class. It is available from API level 23. So, check the SDK version. We will look at the devices below API 23 in a moment.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    val networkCapabilities =  connManager.getNetworkCapabilities(connManager.activeNetwork)
} else {

} 

The method returns null when the device is offline.

if (networkCapabilities == null) {
    Log.d(tagLog, "Device Offline")
    return false
}
else {
    Log.d(tagLog, "Device Online")
    return true
}

For the devices below Marshmallow, we should call getActiveNetworkInfo() method.

public NetworkInfo getActiveNetworkInfo ()

It returns the NetworkInfo object. It provides isConnectedOrConnecting() and isAvailable() functions. If both return true, the user is online.

val activeNetwork = connManager.activeNetworkInfo
if (activeNetwork?.isConnectedOrConnecting == true && activeNetwork.isAvailable) {
    Log.d(tagLog, "Device Online")
    return true
}
else {
    Log.d(tagLog, "Device Offline")
    return false
}

Our final isDeviceOnline() looks like this:

fun isDeviceOnline(context: Context): Boolean {
    val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val networkCapabilities =  connManager.getNetworkCapabilities(connManager.activeNetwork)
        if (networkCapabilities == null) {
            Log.d(tagLog, "Device Offline")
            return false
        }
        else {
            Log.d(tagLog, "Device Online")
            return true
        }
    } else {
        // below Marshmallow
        val activeNetwork = connManager.activeNetworkInfo
        if (activeNetwork?.isConnectedOrConnecting == true && activeNetwork.isAvailable) {
            Log.d(tagLog, "Device Online")
            return true
        }
        else {
            Log.d(tagLog, "Device Offline")
            return false
        }
    }
} 

Call this method from the onCreate():

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val deviceOnline = isDeviceOnline(this.applicationContext)
}

How to Check the Internet Availability in Android?

There are some cases where users are connected to a network, but the network may not have access to the internet. Some of the examples are:

  • User enabled mobile data, but he or she has is no data balance.
  • The device is on a roaming network, and data roaming has been disabled.
  • Some wifi networks ask for sign-in information. In this case, users cannot access the internet until the credentials are provided.

So, we should check if the network has access to the internet. NetworkCapabilities API provides hasCapability() method.

public boolean hasCapability (int capability)

It takes a capability (an integer constant). To determine if the network has internet availability, we will use the following 3 constants:

NET_CAPABILITY_INTERNET: It shows that the network should be able to reach the internet.

NET_CAPABILITY_VALIDATED: It indicates that internet connectivity was successfully detected.

NET_CAPABILITY_NOT_SUSPENDED: It indicates that the network can transfer data.

if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
    networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) &&
    networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
) {
    Log.d(tagLog, "Connected to Internet")
    return true
} else {
    Log.d(tagLog, "Not connected to Internet")
    return false
}

For the devices below Marshmallow (API 23), we can use NetworkInfo.State API.

activeNetwork = connManager.activeNetworkInfo

when (activeNetwork?.state) {
    NetworkInfo.State.CONNECTED -> {
        Log.d(tagLog, " CONNECTED ")
    }
    NetworkInfo.State.CONNECTING -> {
        Log.d(tagLog, " CONNECTING ")
    }
    else -> {
        Log.d(tagLog, "NO CONNECTION")
    }
}

Our isDeviceOnline() method:

private fun isDeviceOnline(context: Context): Boolean {
    val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val networkCapabilities = connManager.getNetworkCapabilities(connManager.activeNetwork)
        if (networkCapabilities == null) {
            Log.d(tagLog, "Device Offline")
            return false
        } else {
            Log.d(tagLog, "Device Online")
            if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
                networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) &&
                networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
            ) {
                Log.d(tagLog, "Connected to Internet")
                return true
            } else {
                Log.d(tagLog, "Not connected to Internet")
                return false
            }
        }
    } else {
        // below Marshmallow
        val activeNetwork = connManager.activeNetworkInfo
        if (activeNetwork?.isConnectedOrConnecting == true && activeNetwork.isAvailable) {
            Log.d(tagLog, "Device Online")
            when (activeNetwork.state) {
                NetworkInfo.State.CONNECTED -> {
                    Log.d(tagLog, " CONNECTED ")
                    return true
                }
                NetworkInfo.State.CONNECTING -> {
                    Log.d(tagLog, " CONNECTING ")
                    return true
                }
                else -> {
                    Log.d(tagLog, "NO Connection")
                    return false
                }
            }
        } else {
            Log.d(tagLog, "Device Offline")
            return false
        }
    }
}

But the above code is not working under some conditions. This is how I tested:

I called the above method in an infinite loop from the onCreate():

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    thread {
        while (true) {
            val deviceOnline = isDeviceOnline(this.applicationContext)
            Log.d(tagLog, "deviceOnline $deviceOnline")
            Thread.sleep(1000)
        }
    }
}

I turned on cellular data and hotspot on my mobile and connected my laptop to the hotspot. I run the above code on a virtual device. The Logcat was showing that the device is online. While the thread is running, I turned off the mobile data. But the Logcat was still displaying the online message.

The above code shows offline when the user connects to a network that has no internet availability. If the user loses the internet after connecting to the network, the code still returns true. Also, on Pixel XL API 22, even if the user connects to a network that cannot access internet, the method still returns true. To fix these problems:

  1. Remove the NetworkInfo.State conditions because they are not working
  2. Send Https request to a server
fun isInternetAvailable(): Boolean {
    val urlConnection =
        URL("https://clients3.google.com/generate_204").openConnection() as HttpsURLConnection
    try {
        urlConnection.setRequestProperty("User-Agent", "Android")
        urlConnection.setRequestProperty("Connection", "close")
        urlConnection.connectTimeout = 1000
        urlConnection.connect()
        return urlConnection.responseCode == 204
    } catch (e: Exception) {
        return false
    }
}

The final code that gives 100% accurate results:

class MainActivity : AppCompatActivity() {

    private val tagLog = javaClass.simpleName as String

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        thread {
            while (true) {
                val deviceOnline = isDeviceOnline(this.applicationContext)
                val internetAvailable = isInternetAvailable()
                Log.d(tagLog, "deviceOnline $deviceOnline")
                Log.d(tagLog, "internetAvailable $internetAvailable")
                Thread.sleep(1000)
            }
        }
    }

    private fun isDeviceOnline(context: Context): Boolean {
        val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val networkCapabilities = connManager.getNetworkCapabilities(connManager.activeNetwork)
            if (networkCapabilities == null) {
                Log.d(tagLog, "Device Offline")
                return false
            } else {
                Log.d(tagLog, "Device Online")
                if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
                    networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) &&
                    networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
                ) {
                    Log.d(tagLog, "Connected to Internet")
                    return true
                } else {
                    Log.d(tagLog, "Not connected to Internet")
                    return false
                }
            }
        } else {
            // below Marshmallow
            val activeNetwork = connManager.activeNetworkInfo
            return activeNetwork?.isConnectedOrConnecting == true && activeNetwork.isAvailable
        }
    }

    fun isInternetAvailable(): Boolean {
        val urlConnection =
            URL("https://clients3.google.com/generate_204").openConnection() as HttpsURLConnection
        try {
            urlConnection.setRequestProperty("User-Agent", "Android")
            urlConnection.setRequestProperty("Connection", "close")
            urlConnection.connectTimeout = 1000
            urlConnection.connect()
            return urlConnection.responseCode == 204
        } catch (e: Exception) {
            return false
        }
    }
}

Bonus: How to Check if the device is Connected to Wifi in Android?

We can check if the device is connected to wifi or a cellular network by using the hasTransport() method of NetworkCapabilities class.

public boolean hasTransport (int transportType)

transportType for the cellular network is TRANSPORT_CELLULAR and wifi is TRANSPORT_WIFI.

For the devices running Marshmallow and lower, the getType() method returns the type of the network.

Here is the full code:

private fun typeOfNetwork(context: Context) {
    val connManager = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        val networkCapabilities = connManager.getNetworkCapabilities(connManager.activeNetwork)
        if (networkCapabilities == null) {
            Log.d(tagLog, "Device Offline")
        } else {
            Log.d(tagLog, "Device Online")
            if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                Log.d(tagLog, "Wifi")
            } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                Log.d(tagLog, "Cellular")
            } else {
                Log.d(tagLog, "Unknown network")
            }
        }
    } else {
        // below Marshmallow
        val activeNetwork = connManager.activeNetworkInfo
        if (activeNetwork?.isConnectedOrConnecting == true && activeNetwork.isAvailable) {
            Log.d(tagLog, "Device Online")
            when (activeNetwork.type) {
                ConnectivityManager.TYPE_WIFI -> {
                    Log.d(tagLog, "Wifi")
                }
                ConnectivityManager.TYPE_MOBILE -> {
                    Log.d(tagLog, "Cellular")
                }
                else -> {
                    Log.d(tagLog, "Unknown network")
                }
            }
        } else {
            Log.d(tagLog, "Device Offline")
        }
    }
}

Call the method from the onCreate():

typeOfNetwork(this.applicationContext)

Note: NetworkInfo has been deprecated in API 29. We are using it in marshmallow (API 23), so we don’t get any problems.

This is how you check the internet connection in Android programmatically. I hope you have learned something new. If you have any doubts, comment below.

Related:

Leave a Comment