Open In App

Programmatically Check the Network Speed in Android

Last Updated : 04 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Network speed can be defined as the total number of packets being exchanged by the client and the server per second, usually calculated in Megabits per second(Mbps). A bit is either a 0 or 1. 1 Megabit implies 1 Million bits. Usually, packet size depends on the protocol and various other factors and usually ranges on a vast scale. In this article, a program is implemented that fetches us Upload and Download speeds with the server. Note that the program is successful when the device is connected to a network.

This program could be used for research as well as for optimization:

  • Research: one could derive the content and the available speeds to correlate the network dependency.
  • Optimization: one could continuously monitor the speed and context, to avoid the connection when not required or reduce the quality of a video being broadcasted depending upon the current speeds.

Approach:

Step 1: Create an Empty activity in Android Studio.

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio.

Check if the primary language selected is Kotlin.


Step 2: Go to the AndroidManifest.xml file and add Permissions

AndroidManifest.xml:

XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

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

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Application"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


Step 3: In the activity_main.xml, add a button. Below is the code for the same.

activity_main.xml:

XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:background="@color/white"
    tools:context=".MainActivity">

    <androidx.cardview.widget.CardView
        android:id="@+id/cardViewSpeed"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        app:cardCornerRadius="8dp"
        app:cardElevation="4dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="16dp">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Speed Test Results"
                android:textSize="18sp"
                android:textStyle="bold"
                android:layout_marginBottom="8dp" />

            <TextView
                android:id="@+id/downloadSpeed"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/data_download"
                android:textSize="16sp"
                android:layout_marginTop="4dp" />

            <TextView
                android:id="@+id/uploadSpeed"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/data_upload"
                android:textSize="16sp"
                android:layout_marginTop="4dp" />

            <TextView
                android:id="@+id/quality"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/data_quality"
                android:textSize="16sp"
                android:layout_marginTop="4dp" />

        </LinearLayout>
    </androidx.cardview.widget.CardView>

    <Button
        android:id="@+id/btnStartTest"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="Start Speed Test"
        android:textAllCaps="false"
        android:padding="12dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cardViewSpeed" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnStartTest" />

    <TextView
        android:id="@+id/status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="@string/data_status"
        android:textSize="14sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/progressBar" />

</androidx.constraintlayout.widget.ConstraintLayout>


Design UI:

Layout


Step 4: Required a class file to calculate Network Speed for the Application.

In this Program we are checking on the a site to checking the response to calculate the speed from it.

SpeedChecker.kt:

Kotlin
package com.gfg.application

import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.InputStream
import java.io.OutputStream
import java.net.HttpURLConnection
import java.net.URL
import kotlin.math.roundToInt

class SpeedChecker(private val context: Context) {

    // Measure download speed (returns speed in Mbps)
    suspend fun measureDownloadSpeed(testUrl: String = "https://www.google.com"): Double = withContext(Dispatchers.IO) {
        try {
            val startTime = System.currentTimeMillis()
            val connection = URL(testUrl).openConnection() as HttpURLConnection
            connection.requestMethod = "GET"
            connection.connectTimeout = 10000
            connection.readTimeout = 10000
            connection.connect()

            val inputStream: InputStream = connection.inputStream
            val buffer = ByteArray(8192)
            var bytesRead: Int
            var totalBytesRead = 0L

            while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                totalBytesRead += bytesRead

                // Stop test after 10 seconds to avoid excessive data usage
                if (System.currentTimeMillis() - startTime > 10000) break
            }

            val endTime = System.currentTimeMillis()
            
            // Convert to seconds
            val duration = (endTime - startTime) / 1000.0 

            inputStream.close()
            connection.disconnect()

            // Calculate speed in Mbps (Megabits per second)
            val speedMbps = ((totalBytesRead * 8) / 1000000.0) / duration
            (speedMbps * 100).roundToInt() / 100.0 
            // Round to 2 decimal places
            
        } catch (e: Exception) {
            e.printStackTrace()
            0.0
        }
    }

    // Measure upload speed (returns speed in Mbps)
    suspend fun measureUploadSpeed(testUrl: String = "https://httpbin.org/post"): Double = withContext(Dispatchers.IO) {
        try {
            val dataSize = 1000000 // 1MB
            
            // Fill with 'a'
            val data = ByteArray(dataSize) { 0x61 } 

            val startTime = System.currentTimeMillis()
            val connection = URL(testUrl).openConnection() as HttpURLConnection
            connection.requestMethod = "POST"
            connection.doOutput = true
            connection.connectTimeout = 10000
            connection.readTimeout = 10000
            connection.connect()

            val outputStream: OutputStream = connection.outputStream
            outputStream.write(data)
            outputStream.flush()
            outputStream.close()

            // Read response to complete the request
            val inputStream: InputStream = connection.inputStream
            val buffer = ByteArray(8192)
            while (inputStream.read(buffer) != -1) { /* Just consuming the response */ }

            val endTime = System.currentTimeMillis()
            
            // Convert to seconds
            val duration = (endTime - startTime) / 1000.0 

            inputStream.close()
            connection.disconnect()

            // Calculate speed in Mbps (Megabits per second)
            val speedMbps = ((dataSize * 8) / 1000000.0) / duration
            (speedMbps * 100).roundToInt() / 100.0 
            // Round to 2 decimal places
            
        } catch (e: Exception) {
            e.printStackTrace()
            0.0
        }
    }

    // Get network quality based on download speed
    fun getNetworkQuality(downloadSpeedMbps: Double): String {
        return when {
            downloadSpeedMbps <= 0 -> "No Connection"
            downloadSpeedMbps < 1 -> "Poor"
            downloadSpeedMbps < 5 -> "Fair"
            downloadSpeedMbps < 10 -> "Good"
            downloadSpeedMbps < 30 -> "Very Good"
            else -> "Excellent"
        }
    }
}


Explanation of the above Program:

  1. Downloads data from the URL and then measures the time of Download/Download Speed.
  2. After that we are sending 1MB dummy data to calculate the Upload speed.


Step 5: Modifying the MainActivity File

In the MainActivity.kt, add the below code. setOnClickListener is added with the button, which when clicked shows the upload speed and download speed as a toast on the screen.

MainActivity.kt:

Kotlin
package com.gfg.application

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    private lateinit var networkSpeedChecker: SpeedChecker

    // UI elements
    private lateinit var tvDownloadSpeed: TextView
    private lateinit var tvUploadSpeed: TextView
    private lateinit var tvQuality: TextView
    private lateinit var tvStatus: TextView
    private lateinit var btnStartTest: Button
    private lateinit var progressBar: ProgressBar

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

        // Initialize NetworkSpeedChecker
        networkSpeedChecker = SpeedChecker(this)

        // Bind UI elements
        tvDownloadSpeed = findViewById(R.id.downloadSpeed)
        tvUploadSpeed = findViewById(R.id.uploadSpeed)
        tvQuality = findViewById(R.id.quality)
        tvStatus = findViewById(R.id.status)
        btnStartTest = findViewById(R.id.btnStartTest)
        progressBar = findViewById(R.id.progressBar)

        // Set up button click listener
        btnStartTest.setOnClickListener {
            startSpeedTest()
        }
    }

    private fun startSpeedTest() {
        // Update UI to show test is running
        progressBar.visibility = View.VISIBLE
        btnStartTest.isEnabled = false
        tvStatus.text = getString(R.string.testing_network_speed)

        // Run speed test in background
        lifecycleScope.launch {

            // Measure download speed
            tvStatus.text = getString(R.string.measuring_download_speed)
            val downloadSpeed = networkSpeedChecker.measureDownloadSpeed()

            // Measure upload speed
            tvStatus.text = getString(R.string.measuring_upload_speed)
            val uploadSpeed = networkSpeedChecker.measureUploadSpeed()

            // Get quality assessment
            val quality = networkSpeedChecker.getNetworkQuality(downloadSpeed)

            // Update UI with results
            runOnUiThread {

                tvDownloadSpeed.text = getString(R.string.download_speed, downloadSpeed)
                tvUploadSpeed.text = getString(R.string.upload_speed, uploadSpeed)
                tvQuality.text = getString(R.string.network_quality, quality)

                // Reset UI state
                progressBar.visibility = View.GONE
                btnStartTest.isEnabled = true
                tvStatus.text = getString(R.string.test_completed)
            }
        }
    }
}

To check the whole application code – Click Here

Demo Video:




Next Article

Similar Reads