You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 14+中如何准确区分4G(LTE)与5G NR(NSA)网络

解决Android 14+下4G LTE与5G NR(NSA)网络识别误判问题

问题背景

在Android 14+设备上,非系统APP仅持有READ_PHONE_STATE权限时,原网络识别逻辑会将实际的4G LTE网络误判为5G NR(NSA),核心原因包括:

  • TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA在4G LTE和5G NR(NSA)场景下均会返回
  • 误判场景中无NR小区可供验证(cellInfos中不存在CellInfoNr)
  • serviceState的nrStates被掩码,无法获取准确状态
  • ##4636#*#*菜单显示NR_NSA但状态栏无5G标识,实际网络为4G LTE

修正后的代码

@SuppressLint("MissingPermission")
suspend fun getNetworkType_2(context: Context, telephonyManager: TelephonyManager): String = suspendCancellableCoroutine { cont ->
    if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED ||
        ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        cont.resume("Permission Required")
        return@suspendCancellableCoroutine
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        CoroutineScope(Dispatchers.Main).launch {

            val listener = object : PhoneStateListener() {
                override fun onDisplayInfoChanged(displayInfo: TelephonyDisplayInfo) {
                    val networkType = telephonyManager.dataNetworkType
                    val voiceType = telephonyManager.voiceNetworkType
                    val overrideType = displayInfo.overrideNetworkType
                    val cellInfos = telephonyManager.allCellInfo ?: emptyList()

                    val nrRegistered = cellInfos.any { it is CellInfoNr && it.isRegistered }
                    val lteRegistered = cellInfos.any { it is CellInfoLte && it.isRegistered }
                    val bands = cellInfos.mapNotNull {
                        when (it) {
                            is CellInfoLte -> (it.cellIdentity as? CellIdentityLte)?.earfcn?.let { earfcn -> "L$earfcn" }
                            is CellInfoNr -> (it.cellIdentity as? CellIdentityNr)?.nrarfcn?.let { nrarfcn -> "N$nrarfcn" }
                            else -> null
                        }
                    }
                    val hasNrBand = bands.any { it.startsWith("N") }

                    telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE)

                    Log.d("GeneralMetrics","Logs for identify 5G NR (NSA)")
                    Log.d("GeneralMetrics","===========================")
                    Log.d("GeneralMetrics","networkType: $networkType")
                    Log.d("GeneralMetrics","voiceType: $voiceType")
                    Log.d("GeneralMetrics","overrideType: $overrideType")
                    Log.d("GeneralMetrics","cellInfos: $cellInfos")
                    Log.d("GeneralMetrics","nrRegistered: $nrRegistered")
                    Log.d("GeneralMetrics","lteRegistered: $lteRegistered")
                    Log.d("GeneralMetrics","bands: $bands")
                    Log.d("GeneralMetrics","hasNrBand: $hasNrBand")
                    Log.d("GeneralMetrics","===========================")

                    val finalNetworkType = when {
                        // 5G NR (SA): 仅注册NR小区
                        nrRegistered && !lteRegistered -> "5G NR (SA)"

                        // 5G NR (NSA): 注册LTE小区,override为NSA,且存在已注册的NR小区或NR频段,语音网络非NR
                        lteRegistered && overrideType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA &&
                                voiceType != TelephonyManager.NETWORK_TYPE_NR && (nrRegistered || hasNrBand) -> "5G NR (NSA)"

                        // 4G (LTE): 注册LTE小区,数据和语音网络均为LTE,或override为NSA但无NR小区
                        lteRegistered && ((networkType == TelephonyManager.NETWORK_TYPE_LTE && voiceType == TelephonyManager.NETWORK_TYPE_LTE) ||
                                (overrideType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA && !nrRegistered && !hasNrBand)) -> "4G (LTE)"

                        // NR fallback
                        networkType == TelephonyManager.NETWORK_TYPE_NR -> "5G NR (Unclassified)"

                        // SA override fallback
                        overrideType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED && nrRegistered -> "5G NR (SA)"

                        else -> getNetworkDescription(networkType, overrideType)
                    }

                    Log.d("NetworkType", "Final Network Type: $finalNetworkType, dataNetworkType=$networkType, overrideType=$overrideType, lteRegistered=$lteRegistered, nrRegistered=$nrRegistered, voiceType=$voiceType")

                    if (cont.isActive) {
                        cont.resume(finalNetworkType)
                    }
                }
            }

            telephonyManager.listen(listener,
                PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or
                        PhoneStateListener.LISTEN_CELL_INFO or
                        PhoneStateListener.LISTEN_DATA_CONNECTION_STATE)

            cont.invokeOnCancellation {
                telephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE)
            }
        }
    } else {
        val networkType = telephonyManager.dataNetworkType
        cont.resume(getNetworkDescription(networkType, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE))
    }
}

fun getNetworkDescription(networkType: Int, overrideType: Int): String {
    return when (overrideType) {
        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> "4G (LTE+ Carrier Aggregation)"
        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> "4G (LTE Advanced Pro)"
        else -> when (networkType) {
            TelephonyManager.NETWORK_TYPE_GSM -> "2G (GSM)"
            TelephonyManager.NETWORK_TYPE_EDGE -> "2G (EDGE)"
            TelephonyManager.NETWORK_TYPE_CDMA -> "2G (CDMA)"
            TelephonyManager.NETWORK_TYPE_1xRTT -> "2G (1xRTT)"
            TelephonyManager.NETWORK_TYPE_IDEN -> "2G (iDEN)"
            TelephonyManager.NETWORK_TYPE_UMTS -> "3G (UMTS)"
            TelephonyManager.NETWORK_TYPE_EVDO_0 -> "3G (EVDO Rev. 0)"
            TelephonyManager.NETWORK_TYPE_EVDO_A -> "3G (EVDO Rev. A)"
            TelephonyManager.NETWORK_TYPE_EVDO_B -> "3G (EVDO Rev. B)"
            TelephonyManager.NETWORK_TYPE_HSDPA -> "3G (HSDPA)"
            TelephonyManager.NETWORK_TYPE_HSUPA -> "3G (HSUPA)"
            TelephonyManager.NETWORK_TYPE_HSPA -> "3G (HSPA)"
            TelephonyManager.NETWORK_TYPE_EHRPD -> "3G (eHRPD)"
            TelephonyManager.NETWORK_TYPE_HSPAP -> "3G (HSPA+)"
            TelephonyManager.NETWORK_TYPE_LTE -> "4G (LTE)"
            TelephonyManager.NETWORK_TYPE_NR -> "5G NR (Unclassified)"
            TelephonyManager.NETWORK_TYPE_UNKNOWN -> "Unknown"
            else -> "Other ($networkType)"
        }
    }
}

关键修改说明

  1. 强化NSA判断条件:在原NSA识别逻辑中新增(nrRegistered || hasNrBand)限制,确保只有存在已注册的NR小区或检测到NR频段时,才判定为5G NR(NSA),直接排除overrideType误报的情况
  2. 覆盖4G特殊场景:新增(overrideType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA && !nrRegistered && !hasNrBand)分支,专门处理overrideType显示NSA但实际无NR小区的4G LTE场景
  3. 保持逻辑兼容:其余网络类型的识别逻辑不变,确保对5G SA、NR fallback等场景的准确性

内容的提问来源于stack exchange,提问作者Chris P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 05:55:54