Use 5G networking

For your application to leverage the enhancements of 5G networks, such as increased bandwidth and lower latency, you can use the following APIs.

Check data bandwidth

When transferring data over a network, it’s important to gauge what bandwidth you have available to you. This can help optimize streaming services or prompt your app to download lower-resolution assets to reduce the impact on the user's network.

You can quickly check the current bandwidth by using ConnectivityManager, as shown in the following code sample:

Kotlin

val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkFilter = NetworkRequest.Builder()
                      .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                      .build()

cm.registerNetworkCallback(networkFilter, object: ConnectivityManager.NetworkCallback() {
    override fun onCapabilitiesChanged(network: Network?, networkCapabilities: NetworkCapabilities?) {
        val bandwidth = networkCapabilities?.linkDownstreamBandwidthKbps ?: -1
    }
})

Java

ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkRequest filter = new NetworkRequest.Builder()
                              .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                              .build();

cm.registerNetworkCallback(filter, new ConnectivityManager.NetworkCallback() {
    @Override
    public void onCapabilitiesChanged(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
        final int approximateBandwidthAvailable = networkCapabilities.getLinkDownstreamBandwidthKbps();
    }
});

Check the type of connection

Often, apps have use cases that leverage not just the available bandwidth, but also other aspects of a 5G network, such as low latency. These aspects can improve responsiveness for multiplayer games and real-time connected devices.

You can get information about capabilities of connected cellular networks using TelephonyManager, as shown in the following code sample:

Kotlin

val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

// Ensure that you have the necessary permissions, since users can revoke this at runtime
if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
    val connectedNetworks = telephonyManager.allCellInfo
            .any { it.isRegistered }
}

Java

TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

List connectedCellularNetworks = new ArrayList<>();

if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
    List allCellInfo = telephonyManager.getAllCellInfo();

    for (CellInfo cellInfo : allCellInfo) {
        if (cellInfo.isRegistered()) {
            connectedCellularNetworks.add(cellInfo);
        }
    }
}

Types of 5G network

Android supports two modes of 5G operation. The following sections cover how to work with each.

Standalone mode (SA)

When an Android device is connected solely to 5G towers and is using 5G connectivity for data and telephony, this is called Standalone mode. If the device is operating in this mode, a CellInfo instance is returned by the getAllCellInfo() method call of type CellInfoNr, which is declared as the primary serving cell.

Kotlin

val isIn5GStandaloneMode = telephonyManager.allCellInfo
       .filterIsInstance(CellInfoNr::class.java)
       .any {
           it.cellConnectionStatus == CellInfo.CONNECTION_PRIMARY_SERVING
       }

Java

TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    return;
}

boolean isConnectedToStandalone5GNetwork = false;

List allCellInfo = telephonyManager.getAllCellInfo();

for (CellInfo cellInfo : allCellInfo) {
    if (cellInfo instanceof CellInfoNr && cellInfo.getCellConnectionStatus() == CellInfo.CONNECTION_PRIMARY_SERVING) {
        isConnectedToStandalone5GNetwork = true;
        break;
    }
}

Non-standalone mode (NSA)

Non-Standalone mode is when an Android device is connected to 4G primary cell with one or more 5G secondary cells providing extra bandwidth.

When operating in this mode, there are at least two CellInfo objects within the returned array: one of type CellInfoLte, declared as the primary serving cell; and one of type CellInfoNr, declared as the secondary serving cell. The secondary serving cell provides only data.

Kotlin

val hasPrimaryLteCell = telephonyManager.allCellInfo
        .filterIsInstance(CellInfoLte::class.java)
        .any {
            it.cellConnectionStatus == CellInfo.CONNECTION_PRIMARY_SERVING
        }

val hasSecondaryNrCell = telephonyManager.allCellInfo
        .filterIsInstance(CellInfoNr::class.java)
        .any {
            it.cellConnectionStatus == CellInfo.CONNECTION_SECONDARY_SERVING
        }

val isIn5GNonStandaloneMode = hasPrimaryLteCell && hasSecondaryNrCell

Java

TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    return;
}

List allCellInfo = telephonyManager.getAllCellInfo();

boolean hasPrimaryLteCell = false;
for (CellInfo cellInfo : allCellInfo) {
    if (cellInfo instanceof CellInfoLte && cellInfo.getCellConnectionStatus() == CellInfo.CONNECTION_PRIMARY_SERVING) {
        hasPrimaryLteCell = true;
        break;
    }
}

boolean hasSecondaryNrCell = false;
for (CellInfo cellInfo : allCellInfo) {
    if (cellInfo instanceof CellInfoNr && cellInfo.getCellConnectionStatus() == CellInfo.CONNECTION_SECONDARY_SERVING) {
        hasSecondaryNrCell = true;
        break;
    }
}

boolean isIn5GNonStandaloneMode = hasPrimaryLteCell && hasSecondaryNrCell;