From 9f49a1953064dd2807100c7037edbbfcf60f28da Mon Sep 17 00:00:00 2001 From: xsean Date: Tue, 23 Dec 2025 12:13:38 +0800 Subject: [PATCH] add network info --- .../java/com/xyzshell/andinfo/libs/MemInfo.kt | 3 +- .../com/xyzshell/andinfo/libs/NetworkInfo.kt | 509 +++++++++++++++++- 2 files changed, 510 insertions(+), 2 deletions(-) diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/MemInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/MemInfo.kt index c8dd9be..abaf916 100644 --- a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/MemInfo.kt +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/MemInfo.kt @@ -1,5 +1,6 @@ package com.xyzshell.andinfo.libs +import android.content.Context import java.io.File import java.io.RandomAccessFile @@ -13,7 +14,7 @@ data class MemoryInfo( val zramUsed: Long // zram 已使用 (字节) ) -class MemInfo { +class MemInfo(private val context: Context){ fun getMemoryInfo(): MemoryInfo { val totalRam = getTotalMemory() diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/NetworkInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/NetworkInfo.kt index e115237..687474d 100644 --- a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/NetworkInfo.kt +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/NetworkInfo.kt @@ -1,4 +1,511 @@ package com.xyzshell.andinfo.libs -class NetworkInfo { +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import android.net.* +import android.net.wifi.ScanResult +import android.net.wifi.WifiManager +import android.net.wifi.WifiInfo +import android.os.Build +import android.telephony.* +import androidx.annotation.RequiresPermission +import androidx.core.app.ActivityCompat +import kotlin.text.compareTo + +/** + * 网络信息工具类,提供当前网络类型、Wi-Fi详情、移动数据详情等获取方法 + */ +class NetworkInfo(private val context: Context) { + + /** + * 当前网络类型枚举 + */ + enum class NetworkType { + WIFI, MOBILE, NONE + } + + /** + * Wi-Fi详细信息数据结构 + */ + data class WifiDetails( + val connected: Boolean, // 是否已连接 + val ssid: String?, // SSID名称 + val bssid: String?, // BSSID + val capabilities: String?, // 加密/功能信息 + val linkSpeedMbps: Int?, // 连接速率 + val rssi: Int?, // dBm信号强度 + val signalLevelPercent: Int?, // 信号强度百分比 + val frequency: Int?, // 频率(MHz) + val channel: Int?, // 信道 + val standard: String?, // 当前连接的标准 + val dhcpServer: String?, // DHCP服务器 + val leaseDuration: Int?, // DHCP租约期限(秒) + val gateway: String?, // 网关 + val subnetMask: String?, // 子网掩码 + val dns1: String?, // DNS1 + val dns2: String?, // DNS2 + val ip: String?, // IPv4地址 + val ipv6: List?, // IPv6地址列表 + val supportedStandards: List?, // 硬件支持的Wi-Fi标准 + val wifiDirect: Boolean?, // 是否支持Wi-Fi Direct + val wifiAware: Boolean?, // 是否支持Wi-Fi Aware + val wifiPasspoint: Boolean?, // 是否支持Passpoint + val support5G: Boolean?, // 是否支持5GHz Wi-Fi + val support6G: Boolean?, // 是否支持6GHz Wi-Fi + //val support60G: Boolean? // 是否支持60GHz Wi-Fi + ) + + /** + * SIM卡信息数据结构 + */ + data class SimInfo( + val slotIndex: Int, // 卡槽索引 + val carrierName: String?, // 运营商名称 + val operator: String?, // 运营商代码(MCC+MNC) + val countryIso: String?, // 国家代码 + val roaming: Boolean, // 是否漫游 + val simState: Int, // SIM卡状态 + val simStateText: String, // SIM卡状态文本 + val phoneType: Int, // 手机类型 + val phoneTypeText: String, // 手机类型文本 + val networkType: Int, // 网络类型 + val networkTypeText: String, // 网络类型文本 + val isEsim: Boolean // 是否eSIM + ) + + /** + * 移动数据详细信息数据结构 + */ + data class MobileDetails( + val dualSim: Boolean, // 是否双卡 + val phoneCount: Int, // 卡槽数量 + val phoneType: Int, // 手机类型 + val esimSupported: Boolean, // 是否支持eSIM + val dataEnabled: Boolean, // 移动数据是否开启 + val dataSim: Int?, // 默认数据网络类型 + val voiceSim: Int?, // 默认语音网络类型 + val smsSim: Int?, // 默认短信卡(Android无直接API) + val simInfos: List // SIM卡信息列表 + ) + + /** + * 获取当前网络类型(Wi-Fi/移动数据/无网络) + */ + fun getCurrentNetworkType(): NetworkType { + val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager + ?: return NetworkType.NONE + + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + val active = cm.activeNetwork ?: return NetworkType.NONE + val caps = cm.getNetworkCapabilities(active) ?: return NetworkType.NONE + when { + caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> NetworkType.WIFI + caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> NetworkType.MOBILE + else -> NetworkType.NONE + } + } else { + @Suppress("DEPRECATION") + when (cm.activeNetworkInfo?.type) { + ConnectivityManager.TYPE_WIFI -> NetworkType.WIFI + ConnectivityManager.TYPE_MOBILE -> NetworkType.MOBILE + else -> NetworkType.NONE + } + } + } catch (e: Exception) { + NetworkType.NONE + } + } + + /** + * 获取当前Wi-Fi详细信息 + * 需要权限: ACCESS_WIFI_STATE, ACCESS_FINE_LOCATION (Android 10+) + */ + fun getWifiDetails(): WifiDetails? { + val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager + ?: return null + + // 检查权限 + if (!checkWifiPermissions()) { + return null + } + + return try { + val wifiInfo = wifiManager.connectionInfo ?: return createEmptyWifiDetails() + val connected = wifiInfo.networkId != -1 + + if (!connected) return createEmptyWifiDetails() + + val dhcp = wifiManager.dhcpInfo + val ssid = wifiInfo.ssid?.removePrefix("\"")?.removeSuffix("\"") + val bssid = wifiInfo.bssid + val linkSpeed = wifiInfo.linkSpeed + val rssi = wifiInfo.rssi + val freq = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + wifiInfo.frequency + } else null + val channel = freq?.let { calculateChannel(it) } + val level = if (rssi != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + WifiManager.calculateSignalLevel(rssi, 100) + } else { + @Suppress("DEPRECATION") + WifiManager.calculateSignalLevel(rssi, 100) + } + } else null + + // 获取加密能力信息 + val capabilities = try { + wifiManager.scanResults.find { it.BSSID == bssid }?.capabilities + } catch (e: SecurityException) { + null + } + + // 获取当前Wi-Fi标准 + val standard = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + when (wifiInfo.wifiStandard) { + ScanResult.WIFI_STANDARD_LEGACY -> "802.11a/b/g" + ScanResult.WIFI_STANDARD_11N -> "802.11n (Wi-Fi 4)" + ScanResult.WIFI_STANDARD_11AC -> "802.11ac (Wi-Fi 5)" + ScanResult.WIFI_STANDARD_11AX -> "802.11ax (Wi-Fi 6/6E)" + else -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + when (wifiInfo.wifiStandard) { + ScanResult.WIFI_STANDARD_11AD -> "802.11ad (WiGig)" + else -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + when (wifiInfo.wifiStandard) { + ScanResult.WIFI_STANDARD_11BE -> "802.11be (Wi-Fi 7)" + else -> "Unknown" + } + } else "Unknown" + } + } else "Unknown" + } + } else null + + val dhcpServer = dhcp?.serverAddress?.let { intToIp(it) } + val leaseDuration = dhcp?.leaseDuration + val gateway = dhcp?.gateway?.let { intToIp(it) } + val subnetMask = dhcp?.netmask?.let { intToIp(it) } + val dns1 = dhcp?.dns1?.let { intToIp(it) } + val dns2 = dhcp?.dns2?.let { intToIp(it) } + val ip = dhcp?.ipAddress?.let { intToIp(it) } + val ipv6 = getIpv6Addresses() + val supportedStandards = getSupportedWifiStandards(wifiManager) + + // Wi-Fi Direct (P2P) 支持 + val wifiDirect = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT) + } else null + + // Wi-Fi Aware (NAN) 支持 + val wifiAware = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE) + } else null + + // Passpoint (Hotspot 2.0) 支持 + val wifiPasspoint = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + try { + wifiManager.isWifiPasspointEnabled + } catch (e: NoSuchMethodError) { + // 某些设备可能不支持此方法 + null + } catch (e: Exception) { + null + } + } else null + + val support5G = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + wifiManager.is5GHzBandSupported + } else null + + val support6G = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + wifiManager.is6GHzBandSupported + } else null + + val support60G = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + wifiManager.is60GHzBandSupported + } else null + + WifiDetails( + connected, ssid, bssid, capabilities, linkSpeed, rssi, level, freq, channel, standard, + dhcpServer, leaseDuration, gateway, subnetMask, dns1, dns2, ip, ipv6, + supportedStandards, wifiDirect, wifiAware, wifiPasspoint, support5G, support6G + ) + } catch (e: Exception) { + null + } + } + + /** + * 获取移动数据详细信息,包括双卡、eSIM、SIM卡状态等 + * 需要权限: READ_PHONE_STATE + */ + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + fun getMobileDetails(): MobileDetails? { + if (!checkPhonePermissions()) { + return null + } + + val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager + ?: return null + + return try { + val subscriptionManager = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as? SubscriptionManager + } else null + + val sims = mutableListOf() + val esimSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + tm.isMultiSimSupported == TelephonyManager.MULTISIM_ALLOWED && + context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC) + } else false + + val phoneType = tm.phoneType + val phoneCount = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + tm.phoneCount + } else 1 + + val dualSim = phoneCount > 1 + + val dataEnabled = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + tm.isDataEnabled + } else { + @Suppress("DEPRECATION") + tm.dataState == TelephonyManager.DATA_CONNECTED + } + + val dataSim = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + tm.dataNetworkType + } else null + + val voiceSim = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + tm.voiceNetworkType + } else null + + val smsSim = null // Android没有直接获取默认短信卡的API + + // 获取每个SIM卡的详细信息 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 && subscriptionManager != null) { + val subInfoList = subscriptionManager.activeSubscriptionInfoList ?: emptyList() + for (info in subInfoList) { + val subTm = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + tm.createForSubscriptionId(info.subscriptionId) + } else tm + + sims.add( + SimInfo( + slotIndex = info.simSlotIndex, + carrierName = info.carrierName?.toString(), + operator = subTm.simOperator, + countryIso = subTm.simCountryIso, + roaming = subTm.isNetworkRoaming, + simState = subTm.simState, + simStateText = getSimStateText(subTm.simState), + phoneType = subTm.phoneType, + phoneTypeText = getPhoneTypeText(subTm.phoneType), + networkType = subTm.networkType, + networkTypeText = getNetworkTypeText(subTm.networkType), + isEsim = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + info.isEmbedded + } else false + ) + ) + } + } else { + // 旧版本系统,只能获取单卡信息 + sims.add( + SimInfo( + slotIndex = 0, + carrierName = tm.simOperatorName, + operator = tm.simOperator, + countryIso = tm.simCountryIso, + roaming = tm.isNetworkRoaming, + simState = tm.simState, + simStateText = getSimStateText(tm.simState), + phoneType = tm.phoneType, + phoneTypeText = getPhoneTypeText(tm.phoneType), + networkType = tm.networkType, + networkTypeText = getNetworkTypeText(tm.networkType), + isEsim = esimSupported + ) + ) + } + + MobileDetails( + dualSim = dualSim, + phoneCount = phoneCount, + phoneType = phoneType, + esimSupported = esimSupported, + dataEnabled = dataEnabled, + dataSim = dataSim, + voiceSim = voiceSim, + smsSim = smsSim, + simInfos = sims + ) + } catch (e: Exception) { + null + } + } + + /** + * int型IP转为字符串 + */ + private fun intToIp(ip: Int): String = + "${ip and 0xFF}.${ip shr 8 and 0xFF}.${ip shr 16 and 0xFF}.${ip shr 24 and 0xFF}" + + /** + * 获取所有IPv6地址 + */ + private fun getIpv6Addresses(): List { + val result = mutableListOf() + try { + val interfaces = java.net.NetworkInterface.getNetworkInterfaces() + for (iface in interfaces) { + if (!iface.isUp || iface.isLoopback) continue + for (addr in iface.inetAddresses) { + if (addr is java.net.Inet6Address && !addr.isLoopbackAddress && !addr.isLinkLocalAddress) { + result.add(addr.hostAddress ?: continue) + } + } + } + } catch (_: Exception) {} + return result + } + + /** + * 获取设备支持的Wi-Fi标准 + */ + private fun getSupportedWifiStandards(wifiManager: WifiManager): List { + val list = mutableListOf() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + if (wifiManager.isWifiStandardSupported(android.net.wifi.ScanResult.WIFI_STANDARD_LEGACY)) { + list.add("802.11a/b/g") + } + if (wifiManager.isWifiStandardSupported(android.net.wifi.ScanResult.WIFI_STANDARD_11N)) { + list.add("802.11n (Wi-Fi 4)") + } + if (wifiManager.isWifiStandardSupported(android.net.wifi.ScanResult.WIFI_STANDARD_11AC)) { + list.add("802.11ac (Wi-Fi 5)") + } + if (wifiManager.isWifiStandardSupported(android.net.wifi.ScanResult.WIFI_STANDARD_11AX)) { + list.add("802.11ax (Wi-Fi 6/6E)") + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (wifiManager.isWifiStandardSupported(android.net.wifi.ScanResult.WIFI_STANDARD_11AD)) { + list.add("802.11ad (WiGig)") + } + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (wifiManager.isWifiStandardSupported(android.net.wifi.ScanResult.WIFI_STANDARD_11BE)) { + list.add("802.11be (Wi-Fi 7)") + } + } + } + return list + } + + /** + * 根据频率计算信道 + */ + private fun calculateChannel(frequency: Int): Int { + return when { + frequency in 2412..2484 -> (frequency - 2407) / 5 // 2.4GHz + frequency in 5170..5825 -> (frequency - 5000) / 5 // 5GHz + frequency in 5955..7115 -> (frequency - 5950) / 5 // 6GHz + else -> -1 + } + } + + /** + * 创建空的Wi-Fi详情对象 + */ + private fun createEmptyWifiDetails() = WifiDetails( + false, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, + null + ) + + /** + * 检查Wi-Fi相关权限 + */ + private fun checkWifiPermissions(): Boolean { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + return ActivityCompat.checkSelfPermission( + context, + Manifest.permission.ACCESS_FINE_LOCATION + ) == PackageManager.PERMISSION_GRANTED + } + return ActivityCompat.checkSelfPermission( + context, + Manifest.permission.ACCESS_WIFI_STATE + ) == PackageManager.PERMISSION_GRANTED + } + + /** + * 检查电话相关权限 + */ + private fun checkPhonePermissions(): Boolean { + return ActivityCompat.checkSelfPermission( + context, + Manifest.permission.READ_PHONE_STATE + ) == PackageManager.PERMISSION_GRANTED + } + + /** + * 获取SIM卡状态文本 + */ + private fun getSimStateText(state: Int): String = when (state) { + TelephonyManager.SIM_STATE_ABSENT -> "无卡" + TelephonyManager.SIM_STATE_PIN_REQUIRED -> "需要PIN" + TelephonyManager.SIM_STATE_PUK_REQUIRED -> "需要PUK" + TelephonyManager.SIM_STATE_NETWORK_LOCKED -> "网络锁定" + TelephonyManager.SIM_STATE_READY -> "就绪" + TelephonyManager.SIM_STATE_NOT_READY -> "未就绪" + TelephonyManager.SIM_STATE_PERM_DISABLED -> "永久禁用" + TelephonyManager.SIM_STATE_CARD_IO_ERROR -> "卡IO错误" + TelephonyManager.SIM_STATE_CARD_RESTRICTED -> "卡受限" + else -> "未知" + } + + /** + * 获取手机类型文本 + */ + private fun getPhoneTypeText(type: Int): String = when (type) { + TelephonyManager.PHONE_TYPE_NONE -> "无" + TelephonyManager.PHONE_TYPE_GSM -> "GSM" + TelephonyManager.PHONE_TYPE_CDMA -> "CDMA" + TelephonyManager.PHONE_TYPE_SIP -> "SIP" + else -> "未知" + } + + /** + * 获取网络类型文本 + */ + private fun getNetworkTypeText(type: Int): String = when (type) { + TelephonyManager.NETWORK_TYPE_GPRS -> "GPRS" + TelephonyManager.NETWORK_TYPE_EDGE -> "EDGE" + TelephonyManager.NETWORK_TYPE_UMTS -> "UMTS (3G)" + TelephonyManager.NETWORK_TYPE_CDMA -> "CDMA" + TelephonyManager.NETWORK_TYPE_EVDO_0 -> "EVDO 0" + TelephonyManager.NETWORK_TYPE_EVDO_A -> "EVDO A" + TelephonyManager.NETWORK_TYPE_1xRTT -> "1xRTT" + TelephonyManager.NETWORK_TYPE_HSDPA -> "HSDPA" + TelephonyManager.NETWORK_TYPE_HSUPA -> "HSUPA" + TelephonyManager.NETWORK_TYPE_HSPA -> "HSPA" + TelephonyManager.NETWORK_TYPE_IDEN -> "iDEN" + TelephonyManager.NETWORK_TYPE_EVDO_B -> "EVDO B" + TelephonyManager.NETWORK_TYPE_LTE -> "LTE (4G)" + TelephonyManager.NETWORK_TYPE_EHRPD -> "eHRPD" + TelephonyManager.NETWORK_TYPE_HSPAP -> "HSPA+" + TelephonyManager.NETWORK_TYPE_GSM -> "GSM" + TelephonyManager.NETWORK_TYPE_TD_SCDMA -> "TD-SCDMA" + TelephonyManager.NETWORK_TYPE_IWLAN -> "IWLAN" + else -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + when (type) { + TelephonyManager.NETWORK_TYPE_NR -> "5G NR" + else -> "未知" + } + } else "未知" + } } \ No newline at end of file