diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..67c2240 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "FSharp.suggestGitignore": false +} \ No newline at end of file diff --git a/CpuInfo核心详细信息使用示例.md b/CpuInfo核心详细信息使用示例.md new file mode 100644 index 0000000..224d8b5 --- /dev/null +++ b/CpuInfo核心详细信息使用示例.md @@ -0,0 +1,263 @@ +# CpuInfo 核心详细信息使用示例 + +## 新增功能说明 + +`CpuInfo` 类新增了获取每个 CPU 核心详细信息的功能,包括: +- 每个核心的最大频率 +- 每个核心的最小频率 +- 每个核心的当前频率 +- 每个核心的速度度量值 +- 可用频率列表 + +## 核心数据类 + +### CoreDetailedInfo +```kotlin +data class CoreDetailedInfo( + val core: Core, // 核心基本信息 + val currentFrequency: Long, // 当前频率(Hz) + val minFrequency: Long, // 最小频率(Hz) + val maxFrequency: Long, // 最大频率(Hz) + val availableFrequencies: List, // 可用频率列表(Hz) + val speedMetric: Double // 速度度量值(GHz) +) +``` + +## 使用示例 + +### 1. 获取所有核心的详细信息 + +```kotlin +val cpuInfo = CpuInfo() + +// 获取所有核心的详细信息 +val detailedCores = cpuInfo.getCoresDetailedInfo() + +detailedCores.forEachIndexed { index, coreInfo -> + println("CPU $index:") + println(" 架构: ${coreInfo.core.uarch.name}") + println(" 供应商: ${coreInfo.core.vendor.name}") + println(" 当前频率: ${coreInfo.currentFrequency / 1_000_000} MHz") + println(" 最小频率: ${coreInfo.minFrequency / 1_000_000} MHz") + println(" 最大频率: ${coreInfo.maxFrequency / 1_000_000} MHz") + println(" 速度度量: ${String.format("%.2f GHz", coreInfo.speedMetric)}") + println(" 可用频率数量: ${coreInfo.availableFrequencies.size}") +} +``` + +### 2. 获取指定核心的详细信息 + +```kotlin +val cpuInfo = CpuInfo() + +// 获取第一个核心(大核)的详细信息 +val core0 = cpuInfo.getCoreDetailedInfo(0) + +core0?.let { + println("大核信息:") + println("当前频率: ${it.currentFrequency / 1_000_000} MHz") + println("最大频率: ${it.maxFrequency / 1_000_000} MHz") + println("最小频率: ${it.minFrequency / 1_000_000} MHz") + println("速度度量: ${it.speedMetric} GHz") +} +``` + +### 3. 获取所有核心的频率列表 + +```kotlin +val cpuInfo = CpuInfo() + +// 获取所有核心的最大频率 +val maxFreqs = cpuInfo.getCoresMaxFrequencies() +println("所有核心最大频率: ${maxFreqs.map { it / 1_000_000 }} MHz") + +// 获取所有核心的最小频率 +val minFreqs = cpuInfo.getCoresMinFrequencies() +println("所有核心最小频率: ${minFreqs.map { it / 1_000_000 }} MHz") + +// 获取所有核心的当前频率 +val currentFreqs = cpuInfo.getCoresCurrentFrequencies() +println("所有核心当前频率: ${currentFreqs.map { it / 1_000_000 }} MHz") + +// 获取所有核心的速度度量值 +val speedMetrics = cpuInfo.getCoresSpeedMetrics() +println("所有核心速度度量: ${speedMetrics.map { String.format("%.2f", it) }} GHz") +``` + +### 4. 分析大小核配置 + +```kotlin +val cpuInfo = CpuInfo() +val detailedCores = cpuInfo.getCoresDetailedInfo() + +// 按最大频率排序,找出大核和小核 +val sortedByFreq = detailedCores.sortedByDescending { it.maxFrequency } + +println("大核(性能核心):") +sortedByFreq.take(2).forEachIndexed { index, core -> + println(" 核心 ${core.core.processorStart}: ${core.core.uarch.name}, ${core.maxFrequency / 1_000_000} MHz") +} + +println("\n小核(效率核心):") +sortedByFreq.takeLast(6).forEach { core -> + println(" 核心 ${core.core.processorStart}: ${core.core.uarch.name}, ${core.maxFrequency / 1_000_000} MHz") +} +``` + +### 5. 监控实时频率变化 + +```kotlin +val cpuInfo = CpuInfo() + +// 创建一个协程来监控频率变化 +lifecycleScope.launch { + while (isActive) { + val currentFreqs = cpuInfo.getCoresCurrentFrequencies() + + println("实时频率:") + currentFreqs.forEachIndexed { index, freq -> + println(" CPU$index: ${freq / 1_000_000} MHz") + } + + delay(1000) // 每秒更新一次 + } +} +``` + +### 6. 计算 CPU 负载百分比 + +```kotlin +val cpuInfo = CpuInfo() +val detailedCores = cpuInfo.getCoresDetailedInfo() + +detailedCores.forEachIndexed { index, core -> + // 计算当前频率占最大频率的百分比 + val loadPercentage = if (core.maxFrequency > 0) { + (core.currentFrequency.toDouble() / core.maxFrequency * 100) + } else { + 0.0 + } + + println("CPU$index 负载: ${String.format("%.1f%%", loadPercentage)}") +} +``` + +### 7. 在 Compose UI 中显示 + +```kotlin +@Composable +fun CpuCoresList() { + val cpuInfo = remember { CpuInfo() } + var detailedCores by remember { mutableStateOf(cpuInfo.getCoresDetailedInfo()) } + + // 自动刷新 + LaunchedEffect(Unit) { + while (true) { + delay(1000) + detailedCores = cpuInfo.getCoresDetailedInfo() + } + } + + LazyColumn { + itemsIndexed(detailedCores) { index, core -> + Card( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = "CPU $index", + style = MaterialTheme.typography.titleMedium + ) + Spacer(modifier = Modifier.height(8.dp)) + + Text("架构: ${core.core.uarch.name}") + Text("当前: ${core.currentFrequency / 1_000_000} MHz") + Text("范围: ${core.minFrequency / 1_000_000} - ${core.maxFrequency / 1_000_000} MHz") + Text("速度度量: ${String.format("%.2f GHz", core.speedMetric)}") + + // 频率进度条 + LinearProgressIndicator( + progress = if (core.maxFrequency > 0) { + core.currentFrequency.toFloat() / core.maxFrequency + } else 0f, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp) + ) + } + } + } + } +} +``` + +## 获取 CPU 性能摘要 + +使用 `text()` 方法可以获取完整的 CPU 信息摘要(包括新增的核心详细信息): + +```kotlin +val cpuInfo = CpuInfo() +val summary = cpuInfo.text() +println(summary) +``` + +输出示例: +``` +=== CPU Basic Info === +Processor Name: Qualcomm Snapdragon 888 +Vendor: ARM +Process: 5nm +Foundry: Samsung +Process Node: Samsung 5LPE +Physical Cores: 8 +Logical Processors: 8 + +=== Core Cluster Configuration === +Big Cores: 1, Max Frequency: 2.84 GHz +Mid Cores: 3, Max Frequency: 2.42 GHz +Little Cores: 4, Max Frequency: 1.80 GHz + +=== Architecture Info === +Architecture: Cortex-X1, Cortex-A78, Cortex-A55 +ABI: arm64-v8a +Supported ABIs: arm64-v8a, armeabi-v7a, armeabi + +=== Performance Metrics === +Performance Level: Flagship +Performance Index: 95.2 +Total Score: 17984.5 +BogoMIPS: 38.40 + +=== Governor === +Current Governor: schedutil +Available Governors: schedutil, performance, powersave + +=== Core Detailed Info === +CPU0: Current=2.84 GHz, Range=300 MHz-2.84 GHz, Metric=2.84 GHz, Arch=Cortex-X1 +CPU1: Current=2.42 GHz, Range=300 MHz-2.42 GHz, Metric=2.42 GHz, Arch=Cortex-A78 +... +``` + +## 注意事项 + +1. **频率单位**: 所有频率值都以 Hz(赫兹)为单位返回 + - 转换为 MHz: `frequency / 1_000_000` + - 转换为 GHz: `frequency / 1_000_000_000.0` + +2. **权限**: 读取频率信息不需要特殊权限 + +3. **实时性**: `currentFrequency` 是实时读取的,会随 CPU 负载变化而变化 + +4. **可用频率**: 某些设备可能不提供 `availableFrequencies` 列表,返回空列表 + +5. **速度度量**: `speedMetric` 是根据最大频率计算的,单位为 GHz,可以用来比较不同核心的性能 + +6. **中英文**: 所有返回的文本信息已改为英文,中文保留在注释中 + +## 兼容性 + +- 最低 Android 版本: 与原 CpuInfo 类相同 +- 支持所有架构: ARM, ARM64, x86, x86_64 +- 向后兼容: 所有原有方法保持不变 diff --git a/DisplayInfo屏幕尺寸使用示例.md b/DisplayInfo屏幕尺寸使用示例.md new file mode 100644 index 0000000..68844f7 --- /dev/null +++ b/DisplayInfo屏幕尺寸使用示例.md @@ -0,0 +1,523 @@ +# DisplayInfo 屏幕尺寸功能使用示例 + +## 新增功能说明 + +`DisplayInfo` 类新增了获取屏幕物理尺寸的功能,支持以下单位: +- **英寸 (inches)**: 国际通用的屏幕尺寸单位 +- **毫米 (mm)**: 公制单位,更精确的物理尺寸 + +可以获取: +- 对角线尺寸(屏幕大小) +- 宽度尺寸 +- 高度尺寸 + +## 核心数据类 + +### ScreenSize +```kotlin +data class ScreenSize( + val diagonalInches: Double, // 对角线尺寸(英寸) + val diagonalMm: Double, // 对角线尺寸(毫米) + val widthInches: Double, // 宽度(英寸) + val widthMm: Double, // 宽度(毫米) + val heightInches: Double, // 高度(英寸) + val heightMm: Double // 高度(毫米) +) +``` + +### DefaultDisplayInfo (已更新) +现在包含 `screenSize: ScreenSize` 字段,提供完整的屏幕物理尺寸信息。 + +## 使用示例 + +### 1. 获取完整的屏幕尺寸信息 + +```kotlin +val displayInfo = DisplayInfo(context) + +// 获取完整的屏幕尺寸信息 +val screenSize = displayInfo.getScreenSize() + +screenSize?.let { + println("=== Screen Size ===") + println("Diagonal: ${String.format("%.2f", it.diagonalInches)}\" (${String.format("%.1f", it.diagonalMm)} mm)") + println("Width: ${String.format("%.2f", it.widthInches)}\" (${String.format("%.1f", it.widthMm)} mm)") + println("Height: ${String.format("%.2f", it.heightInches)}\" (${String.format("%.1f", it.heightMm)} mm)") +} +``` + +输出示例: +``` +=== Screen Size === +Diagonal: 6.67" (169.4 mm) +Width: 2.91" (73.9 mm) +Height: 6.32" (160.5 mm) +``` + +### 2. 获取屏幕对角线尺寸 + +```kotlin +val displayInfo = DisplayInfo(context) + +// 获取对角线尺寸(英寸) +val diagonalInches = displayInfo.getScreenDiagonalInches() +println("Screen Size: ${String.format("%.2f", diagonalInches)}\"") + +// 获取对角线尺寸(毫米) +val diagonalMm = displayInfo.getScreenDiagonalMm() +println("Screen Size: ${String.format("%.1f", diagonalMm)} mm") +``` + +输出示例: +``` +Screen Size: 6.67" +Screen Size: 169.4 mm +``` + +### 3. 获取屏幕宽度和高度 + +```kotlin +val displayInfo = DisplayInfo(context) + +// 获取宽度 +val widthInches = displayInfo.getScreenWidthInches() +val widthMm = displayInfo.getScreenWidthMm() +println("Screen Width: ${String.format("%.2f", widthInches)}\" / ${String.format("%.1f", widthMm)} mm") + +// 获取高度 +val heightInches = displayInfo.getScreenHeightInches() +val heightMm = displayInfo.getScreenHeightMm() +println("Screen Height: ${String.format("%.2f", heightInches)}\" / ${String.format("%.1f", heightMm)} mm") +``` + +输出示例: +``` +Screen Width: 2.91" / 73.9 mm +Screen Height: 6.32" / 160.5 mm +``` + +### 4. 从 DefaultDisplayInfo 获取完整信息 + +```kotlin +val displayInfo = DisplayInfo(context) + +val defaultDisplayInfo = displayInfo.getDefaultDisplayInfo() + +defaultDisplayInfo?.let { info -> + println("=== Display Information ===") + println("Name: ${info.name}") + println("Resolution: ${info.widthPixels} x ${info.heightPixels}") + println("Density: ${info.densityDpi} dpi") + println("PPI: ${String.format("%.1f", info.ppi)}") + println("Refresh Rate: ${info.refreshRate} Hz") + + // 屏幕尺寸 + println("\n=== Screen Size ===") + println("Diagonal: ${String.format("%.2f", info.screenSize.diagonalInches)}\"") + println("Size: ${String.format("%.2f", info.screenSize.widthInches)}\" x ${String.format("%.2f", info.screenSize.heightInches)}\"") + println("Size (mm): ${String.format("%.1f", info.screenSize.widthMm)} x ${String.format("%.1f", info.screenSize.heightMm)} mm") + + // HDR 信息 + if (info.isHdr) { + println("\n=== HDR Support ===") + println("HDR Types: ${info.hdrTypes.joinToString(", ")}") + } + + // 广色域 + if (info.isWideColorGamut) { + println("Wide Color Gamut: Supported") + } +} +``` + +输出示例: +``` +=== Display Information === +Name: Built-in Screen +Resolution: 1080 x 2400 +Density: 393 dpi +PPI: 395.6 +Refresh Rate: 120.0 Hz + +=== Screen Size === +Diagonal: 6.67" +Size: 2.91" x 6.32" +Size (mm): 73.9 x 160.5 mm + +=== HDR Support === +HDR Types: HDR10, HDR10+ + +Wide Color Gamut: Supported +``` + +### 5. 计算屏幕纵横比 + +```kotlin +val displayInfo = DisplayInfo(context) + +val screenSize = displayInfo.getScreenSize() + +screenSize?.let { + // 计算纵横比 + val aspectRatio = it.widthInches / it.heightInches + + // 判断常见纵横比 + val ratioName = when { + aspectRatio.isCloseTo(9.0 / 16.0, 0.01) -> "16:9" + aspectRatio.isCloseTo(9.0 / 18.0, 0.01) -> "18:9 (2:1)" + aspectRatio.isCloseTo(9.0 / 19.5, 0.01) -> "19.5:9" + aspectRatio.isCloseTo(9.0 / 20.0, 0.01) -> "20:9" + aspectRatio.isCloseTo(9.0 / 21.0, 0.01) -> "21:9" + aspectRatio.isCloseTo(3.0 / 4.0, 0.01) -> "4:3" + else -> String.format("%.2f:1", 1.0 / aspectRatio) + } + + println("Screen Aspect Ratio: $ratioName") +} + +// 辅助函数 +fun Double.isCloseTo(target: Double, tolerance: Double): Boolean { + return kotlin.math.abs(this - target) < tolerance +} +``` + +### 6. 计算屏幕面积 + +```kotlin +val displayInfo = DisplayInfo(context) + +val screenSize = displayInfo.getScreenSize() + +screenSize?.let { + // 计算面积(平方英寸) + val areaInches = it.widthInches * it.heightInches + + // 计算面积(平方厘米) + val areaCm = (it.widthMm / 10.0) * (it.heightMm / 10.0) + + println("Screen Area: ${String.format("%.2f", areaInches)} in²") + println("Screen Area: ${String.format("%.2f", areaCm)} cm²") +} +``` + +输出示例: +``` +Screen Area: 18.39 in² +Screen Area: 118.65 cm² +``` + +### 7. 在 Jetpack Compose 中显示 + +```kotlin +@Composable +fun ScreenSizeCard() { + val context = LocalContext.current + val displayInfo = remember { DisplayInfo(context) } + val defaultDisplayInfo = remember { displayInfo.getDefaultDisplayInfo() } + + defaultDisplayInfo?.let { info -> + Card( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + elevation = CardDefaults.cardElevation(4.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = "Display Information", + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold + ) + + Spacer(modifier = Modifier.height(16.dp)) + + // 分辨率和密度 + InfoSection(title = "Resolution & Density") { + InfoRow("Resolution", "${info.widthPixels} x ${info.heightPixels} px") + InfoRow("Density", "${info.densityDpi} dpi") + InfoRow("PPI", String.format("%.1f", info.ppi)) + } + + Spacer(modifier = Modifier.height(12.dp)) + + // 屏幕尺寸 + InfoSection(title = "Screen Size") { + InfoRow( + "Diagonal", + String.format("%.2f\" (%.1f mm)", + info.screenSize.diagonalInches, + info.screenSize.diagonalMm + ) + ) + InfoRow( + "Width", + String.format("%.2f\" (%.1f mm)", + info.screenSize.widthInches, + info.screenSize.widthMm + ) + ) + InfoRow( + "Height", + String.format("%.2f\" (%.1f mm)", + info.screenSize.heightInches, + info.screenSize.heightMm + ) + ) + } + + Spacer(modifier = Modifier.height(12.dp)) + + // 刷新率 + InfoSection(title = "Refresh Rate") { + InfoRow("Current", "${info.refreshRate.toInt()} Hz") + if (info.supportedRefreshRates.size > 1) { + InfoRow( + "Supported", + info.supportedRefreshRates.joinToString(", ") { "${it.toInt()} Hz" } + ) + } + } + + // HDR 和色域 + if (info.isHdr || info.isWideColorGamut) { + Spacer(modifier = Modifier.height(12.dp)) + + InfoSection(title = "Advanced Features") { + if (info.isHdr) { + InfoRow("HDR", info.hdrTypes.joinToString(", ")) + } + if (info.isWideColorGamut) { + InfoRow("Color Gamut", "Wide Color Gamut") + } + } + } + } + } + } +} + +@Composable +fun InfoSection(title: String, content: @Composable () -> Unit) { + Column { + Text( + text = title, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.height(8.dp)) + content() + } +} + +@Composable +fun InfoRow(label: String, value: String) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = label, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Text( + text = value, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium, + textAlign = TextAlign.End, + modifier = Modifier.weight(1f, fill = false) + ) + } +} +``` + +### 8. 比较设备屏幕大小 + +```kotlin +fun compareScreenSizes(context: Context) { + val displayInfo = DisplayInfo(context) + val screenSize = displayInfo.getScreenSize() ?: return + + println("=== Screen Size Comparison ===") + + val diagonal = screenSize.diagonalInches + + val category = when { + diagonal < 4.5 -> "Compact Phone (< 4.5\")" + diagonal < 5.5 -> "Standard Phone (4.5\" - 5.5\")" + diagonal < 6.5 -> "Large Phone (5.5\" - 6.5\")" + diagonal < 7.5 -> "Phablet (6.5\" - 7.5\")" + diagonal < 10.0 -> "Small Tablet (7.5\" - 10\")" + diagonal < 13.0 -> "Standard Tablet (10\" - 13\")" + else -> "Large Tablet (> 13\")" + } + + println("Device Category: $category") + println("Screen Diagonal: ${String.format("%.2f", diagonal)}\"") + + // 与常见设备比较 + println("\nComparison with common sizes:") + println("iPhone 15 Pro Max: ~6.7\"") + println("Samsung Galaxy S24 Ultra: ~6.8\"") + println("iPad Pro 11\": ~11\"") + println("iPad Pro 12.9\": ~12.9\"") +} +``` + +### 9. 计算最佳查看距离 + +```kotlin +fun calculateOptimalViewingDistance(context: Context) { + val displayInfo = DisplayInfo(context) + val defaultInfo = displayInfo.getDefaultDisplayInfo() ?: return + + // 基于 PPI 和屏幕尺寸计算最佳查看距离 + // 一般建议:对于 300+ PPI,最佳查看距离约为屏幕对角线的 1.5-2 倍 + + val diagonalInches = defaultInfo.screenSize.diagonalInches + val ppi = defaultInfo.ppi + + val minDistance = diagonalInches * 1.5 + val maxDistance = diagonalInches * 2.0 + + // 转换为厘米 + val minDistanceCm = minDistance * 2.54 + val maxDistanceCm = maxDistance * 2.54 + + println("=== Optimal Viewing Distance ===") + println("Screen: ${String.format("%.2f", diagonalInches)}\" @ ${String.format("%.0f", ppi)} PPI") + println("Recommended distance: ${String.format("%.1f", minDistanceCm)} - ${String.format("%.1f", maxDistanceCm)} cm") + println(" (${String.format("%.1f", minDistance)} - ${String.format("%.1f", maxDistance)} inches)") +} +``` + +### 10. 检测屏幕类型 + +```kotlin +fun detectScreenType(context: Context): String { + val displayInfo = DisplayInfo(context) + val defaultInfo = displayInfo.getDefaultDisplayInfo() ?: return "Unknown" + + val diagonal = defaultInfo.screenSize.diagonalInches + val widthPixels = defaultInfo.widthPixels + val heightPixels = defaultInfo.heightPixels + val ppi = defaultInfo.ppi + + // 计算纵横比 + val aspectRatio = widthPixels.toDouble() / heightPixels.toDouble() + + return buildString { + // 设备类型 + append(when { + diagonal < 7.0 -> "Smartphone" + diagonal < 10.0 -> "Phablet/Small Tablet" + else -> "Tablet" + }) + + append(" | ") + + // 屏幕质量 + append(when { + ppi >= 500 -> "Ultra High Density" + ppi >= 400 -> "Very High Density" + ppi >= 300 -> "High Density" + ppi >= 200 -> "Medium Density" + else -> "Low Density" + }) + + append(" | ") + + // 纵横比类型 + append(when { + aspectRatio < 0.5 -> "Ultra-wide (21:9+)" + aspectRatio < 0.52 -> "Wide (20:9)" + aspectRatio < 0.54 -> "Wide (19.5:9)" + aspectRatio < 0.58 -> "Standard (18:9)" + aspectRatio < 0.60 -> "Standard (16:9)" + else -> "Traditional (4:3)" + }) + } +} + +// 使用示例 +val screenType = detectScreenType(context) +println("Screen Type: $screenType") +// 输出: "Smartphone | Very High Density | Wide (20:9)" +``` + +## 技术细节 + +### 计算方法 + +1. **对角线尺寸**: + ``` + diagonal_inches = √(width_inches² + height_inches²) + ``` + +2. **宽度/高度转换**: + ``` + width_inches = width_pixels / xdpi + height_inches = height_pixels / ydpi + ``` + +3. **英寸到毫米转换**: + ``` + millimeters = inches × 25.4 + ``` + +### 精确度说明 + +- 计算基于设备报告的 `xdpi` 和 `ydpi` 值 +- 大多数设备提供准确的 DPI 信息 +- 某些低端设备可能报告不准确的 DPI,导致尺寸计算偏差 +- 对角线尺寸通常误差在 ±0.1 英寸以内 + +## 注意事项 + +1. **DPI 准确性**:计算依赖于系统报告的 DPI 值,大多数现代设备提供准确的值 + +2. **单位转换**: + - 1 英寸 = 25.4 毫米 + - 1 英寸 = 2.54 厘米 + +3. **屏幕对角线**:通常所说的屏幕尺寸指的是对角线长度(如 6.7 英寸手机) + +4. **无需权限**:获取屏幕尺寸信息不需要任何特殊权限 + +5. **兼容性**:支持所有 Android 版本,使用标准 Android API + +6. **性能**:计算是轻量级的,可以频繁调用而不影响性能 + +## 常见屏幕尺寸参考 + +### 智能手机 +- **紧凑型**: 4.0" - 5.0" +- **标准型**: 5.0" - 6.0" +- **大屏型**: 6.0" - 6.5" +- **超大屏**: 6.5" - 7.0" + +### 平板电脑 +- **小型平板**: 7" - 8" +- **标准平板**: 9" - 10" +- **大型平板**: 11" - 13" + +### 物理尺寸示例 +- **iPhone 15 Pro Max**: 6.7" (约 170 mm) +- **Samsung Galaxy S24 Ultra**: 6.8" (约 173 mm) +- **iPad Air**: 10.9" (约 277 mm) +- **iPad Pro**: 12.9" (约 328 mm) + +## 扩展用途 + +屏幕尺寸信息可以用于: +- UI 布局自适应 +- 字体大小调整 +- 图片资源选择 +- 视频播放优化 +- 游戏控制布局 +- 阅读体验优化 +- 设备分类统计 +- 用户体验研究 diff --git a/GpuInfo增强功能使用示例.md b/GpuInfo增强功能使用示例.md new file mode 100644 index 0000000..798d07f --- /dev/null +++ b/GpuInfo增强功能使用示例.md @@ -0,0 +1,472 @@ +# GpuInfo 增强功能使用示例 + +## 新增功能说明 + +`GpuInfo` 类已增强并修复以下功能: +- 修复了 `getOpenGLVersion()` 可能返回空值的问题 +- 新增 GPU 最大频率获取 +- 新增 GPU 架构信息 +- 新增 GPU 缓存大小 +- 新增 GPU 内存带宽 +- 新增计算单元和着色单元数量 +- 所有返回文本已国际化为英文 + +## 核心数据类 + +### GpuDetailedInfo +```kotlin +data class GpuDetailedInfo( + val maxFrequency: Int?, // 最大频率(MHz) + val architecture: String?, // 架构名称 + val cacheSize: Int?, // 缓存大小(KB) + val bandwidth: Double?, // 内存带宽(GB/s) + val computeUnits: Int?, // 计算单元数量 + val shadingUnits: Int? // 着色单元数量 +) +``` + +## 支持的 GPU 型号 + +### Qualcomm Adreno 系列 +- Adreno 740, 730, 725, 720, 710, 702 +- Adreno 690, 660, 650, 640, 630, 620 + +### ARM Mali 系列 +- Mali-G720, G715, G710, G610 +- Mali-G78, G77, G76, G72, G71 +- Mali-G68, G57, G52, G51 + +### Apple GPU +- A17/M3, A16/M2, A15/M1 + +### PowerVR 系列 +- PowerVR GE8320 + +## 使用示例 + +### 1. 获取基本 GPU 信息 + +```kotlin +val gpuInfo = GpuInfo(context) + +// 获取供应商 +val vendor = gpuInfo.getVendorName() +println("GPU Vendor: $vendor") + +// 获取型号 +val renderer = gpuInfo.getRendererName() +println("GPU Model: $renderer") + +// 获取设备类型 +val deviceType = gpuInfo.getDeviceTypeDescription() +println("Device Type: $deviceType") + +// 获取 OpenGL ES 版本(已修复) +val glVersion = gpuInfo.getOpenGLVersion() +println("OpenGL ES Version: $glVersion") + +// 获取 Vulkan 版本 +val vkVersion = gpuInfo.getVulkanApiVersion() +println("Vulkan Version: $vkVersion") +``` + +### 2. 获取 GPU 详细规格 + +```kotlin +val gpuInfo = GpuInfo(context) + +// 获取完整的 GPU 详细信息 +val detailedInfo = gpuInfo.getGpuDetailedInfo() + +println("=== GPU Specifications ===") +println("Architecture: ${detailedInfo.architecture}") +println("Max Frequency: ${detailedInfo.maxFrequency} MHz") +println("Cache Size: ${detailedInfo.cacheSize} KB") +println("Memory Bandwidth: ${detailedInfo.bandwidth} GB/s") +println("Compute Units: ${detailedInfo.computeUnits}") +println("Shading Units: ${detailedInfo.shadingUnits}") +``` + +### 3. 获取单个规格属性 + +```kotlin +val gpuInfo = GpuInfo(context) + +// 获取最大频率 +val maxFreq = gpuInfo.getMaxFrequency() +println("Max Frequency: ${maxFreq ?: "Unknown"} MHz") + +// 获取架构 +val arch = gpuInfo.getArchitecture() +println("Architecture: ${arch ?: "Unknown"}") + +// 获取缓存大小 +val cache = gpuInfo.getCacheSize() +println("Cache: ${cache ?: "Unknown"} KB") + +// 获取带宽 +val bandwidth = gpuInfo.getBandwidth() +println("Bandwidth: ${bandwidth ?: "Unknown"} GB/s") + +// 获取计算单元 +val computeUnits = gpuInfo.getComputeUnits() +println("Compute Units: ${computeUnits ?: "Unknown"}") + +// 获取着色单元 +val shadingUnits = gpuInfo.getShadingUnits() +println("Shading Units: ${shadingUnits ?: "Unknown"}") +``` + +### 4. 获取完整的 GPU 摘要 + +```kotlin +val gpuInfo = GpuInfo(context) + +// 获取格式化的完整摘要 +val summary = gpuInfo.getGpuSummary() +println(summary) +``` + +输出示例: +``` +=== GPU Basic Info === +Vendor: Qualcomm +Model: Adreno (TM) 730 +Type: Integrated GPU + +=== GPU Specifications === +Architecture: Adreno 730 +Max Frequency: 818 MHz +Cache Size: 1536 KB +Memory Bandwidth: 44.8 GB/s +Compute Units: 6 +Shading Units: 768 + +=== Vulkan Info === +Supported: Yes +API Version: 1.3.0 +Driver Version: 512 + +--- Vulkan Device --- +Device Name: Adreno (TM) 730 +Device ID: 43051011 +Vendor ID: 0x5143 +Registered Vendor: Qualcomm +Device Type: Integrated GPU +API Version: 1.3.0 + +=== OpenGL ES Info === +Vendor: Qualcomm +Renderer: Adreno (TM) 730 +Version: OpenGL ES 3.2 +Extension Count: 247 + +=== EGL Info === +Vendor: Qualcomm +Version: 1.5 +Client API: OpenGL_ES +Extension Count: 52 +``` + +### 5. 计算 GPU 性能指标 + +```kotlin +val gpuInfo = GpuInfo(context) +val detailedInfo = gpuInfo.getGpuDetailedInfo() + +// 计算理论峰值性能(GFLOPS) +// 公式:着色单元 * 频率 * 2 (FMA operations) +val theoreticalGFLOPS = detailedInfo.shadingUnits?.let { units -> + detailedInfo.maxFrequency?.let { freq -> + (units * freq * 2) / 1000.0 + } +} + +println("Theoretical Peak Performance: ${theoreticalGFLOPS?.let { + String.format("%.1f GFLOPS", it) +} ?: "Unknown"}") + +// 计算带宽利用率(假设某个应用需要 10 GB/s) +val requiredBandwidth = 10.0 +val bandwidthUtilization = detailedInfo.bandwidth?.let { + (requiredBandwidth / it * 100).coerceIn(0.0, 100.0) +} + +println("Bandwidth Utilization: ${bandwidthUtilization?.let { + String.format("%.1f%%", it) +} ?: "Unknown"}") +``` + +### 6. 比较不同 GPU + +```kotlin +fun compareGpus(gpu1Name: String, gpu2Name: String) { + val gpuInfo = GpuInfo(context) + + // 模拟获取两个 GPU 的信息(实际使用中,这些可能来自数据库) + val spec1 = gpuInfo.getGpuSpecsByRenderer(gpu1Name.lowercase()) + val spec2 = gpuInfo.getGpuSpecsByRenderer(gpu2Name.lowercase()) + + println("=== GPU Comparison ===") + println("GPU 1: $gpu1Name") + println(" Max Freq: ${spec1.maxFrequency} MHz") + println(" Bandwidth: ${spec1.bandwidth} GB/s") + println(" Compute Units: ${spec1.computeUnits}") + + println("\nGPU 2: $gpu2Name") + println(" Max Freq: ${spec2.maxFrequency} MHz") + println(" Bandwidth: ${spec2.bandwidth} GB/s") + println(" Compute Units: ${spec2.computeUnits}") + + // 简单性能比较 + val perfScore1 = (spec1.maxFrequency ?: 0) * (spec1.computeUnits ?: 0) + val perfScore2 = (spec2.maxFrequency ?: 0) * (spec2.computeUnits ?: 0) + + println("\nPerformance Score:") + println(" $gpu1Name: $perfScore1") + println(" $gpu2Name: $perfScore2") + + if (perfScore1 > perfScore2) { + val diff = ((perfScore1 - perfScore2).toDouble() / perfScore2 * 100) + println(" $gpu1Name is ${String.format("%.1f%%", diff)} faster") + } else if (perfScore2 > perfScore1) { + val diff = ((perfScore2 - perfScore1).toDouble() / perfScore1 * 100) + println(" $gpu2Name is ${String.format("%.1f%%", diff)} faster") + } +} + +// 使用示例 +compareGpus("Adreno 730", "Mali-G78") +``` + +### 7. 在 Jetpack Compose 中显示 + +```kotlin +@Composable +fun GpuInfoCard() { + val context = LocalContext.current + val gpuInfo = remember { GpuInfo(context) } + val detailedInfo = remember { gpuInfo.getGpuDetailedInfo() } + + Card( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + elevation = CardDefaults.cardElevation(4.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = "GPU Information", + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold + ) + + Spacer(modifier = Modifier.height(16.dp)) + + // 基本信息 + InfoRow("Vendor", gpuInfo.getVendorName() ?: "Unknown") + InfoRow("Model", gpuInfo.getRendererName() ?: "Unknown") + InfoRow("Type", gpuInfo.getDeviceTypeDescription() ?: "Unknown") + + Divider(modifier = Modifier.padding(vertical = 8.dp)) + + // 详细规格 + Text( + text = "Specifications", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + + Spacer(modifier = Modifier.height(8.dp)) + + detailedInfo.architecture?.let { + InfoRow("Architecture", it) + } + detailedInfo.maxFrequency?.let { + InfoRow("Max Frequency", "$it MHz") + } + detailedInfo.cacheSize?.let { + InfoRow("Cache Size", "$it KB") + } + detailedInfo.bandwidth?.let { + InfoRow("Bandwidth", String.format("%.1f GB/s", it)) + } + detailedInfo.computeUnits?.let { + InfoRow("Compute Units", it.toString()) + } + detailedInfo.shadingUnits?.let { + InfoRow("Shading Units", it.toString()) + } + + Divider(modifier = Modifier.padding(vertical = 8.dp)) + + // API 信息 + Text( + text = "API Support", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + + Spacer(modifier = Modifier.height(8.dp)) + + InfoRow("OpenGL ES", gpuInfo.getOpenGLVersion() ?: "Unknown") + InfoRow("Vulkan", gpuInfo.getVulkanApiVersion() ?: "Not Supported") + InfoRow("EGL", gpuInfo.getEglVersion() ?: "Unknown") + } + } +} + +@Composable +fun InfoRow(label: String, value: String) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = label, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Text( + text = value, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium + ) + } +} +``` + +### 8. 检测 GPU 能力 + +```kotlin +fun checkGpuCapabilities(context: Context) { + val gpuInfo = GpuInfo(context) + val detailedInfo = gpuInfo.getGpuDetailedInfo() + + println("=== GPU Capabilities Check ===") + + // 检查是否适合游戏 + val isGoodForGaming = (detailedInfo.maxFrequency ?: 0) > 600 && + (detailedInfo.computeUnits ?: 0) >= 4 && + (detailedInfo.bandwidth ?: 0.0) > 25.0 + + println("Suitable for Gaming: ${if (isGoodForGaming) "Yes" else "No"}") + + // 检查是否支持高端图形 + val supportsHighEndGraphics = gpuInfo.isVulkanSupported() && + (detailedInfo.shadingUnits ?: 0) > 512 + + println("High-End Graphics Support: ${if (supportsHighEndGraphics) "Yes" else "No"}") + + // 检查 AI/ML 能力 + val goodForAI = (detailedInfo.computeUnits ?: 0) >= 6 && + (detailedInfo.bandwidth ?: 0.0) > 40.0 + + println("Good for AI/ML: ${if (goodForAI) "Yes" else "No"}") + + // 推荐图形质量设置 + val recommendedQuality = when { + (detailedInfo.maxFrequency ?: 0) > 800 && + (detailedInfo.computeUnits ?: 0) >= 6 -> "Ultra" + (detailedInfo.maxFrequency ?: 0) > 650 && + (detailedInfo.computeUnits ?: 0) >= 4 -> "High" + (detailedInfo.maxFrequency ?: 0) > 500 -> "Medium" + else -> "Low" + } + + println("Recommended Graphics Quality: $recommendedQuality") +} +``` + +### 9. OpenGL ES 版本检测增强 + +```kotlin +val gpuInfo = GpuInfo(context) + +// 修复后的 getOpenGLVersion() 方法 +val glVersion = gpuInfo.getOpenGLVersion() + +when { + glVersion == null || glVersion == "Unknown" -> { + println("OpenGL ES: Not available or unknown") + } + glVersion.contains("3.2") -> { + println("OpenGL ES 3.2: Full support for modern graphics") + } + glVersion.contains("3.1") -> { + println("OpenGL ES 3.1: Good support for most features") + } + glVersion.contains("3.0") -> { + println("OpenGL ES 3.0: Basic modern graphics support") + } + glVersion.contains("2.0") -> { + println("OpenGL ES 2.0: Legacy support only") + } + else -> { + println("OpenGL ES: $glVersion") + } +} +``` + +## 注意事项 + +1. **规格数据来源**: GPU 规格信息基于公开的硬件数据库,对于未识别的 GPU 型号,规格字段将返回 `null` + +2. **OpenGL ES 版本修复**: + - 修复了可能返回 `null` 的问题 + - 如果无法从 EGL 获取,会尝试从 Vulkan 推断 + - 最坏情况返回 "Unknown" 而不是 `null` + +3. **精确性**: + - 频率和带宽值是理论最大值,实际运行时可能更低 + - 不同设备批次可能有轻微差异 + +4. **权限**: 获取 GPU 信息不需要特殊权限 + +5. **性能**: + - GPU 信息获取是轻量级操作 + - 建议在应用启动时获取一次并缓存 + +6. **兼容性**: + - 支持 Android 5.0 (API 21) 及以上 + - Vulkan 信息需要 Android 7.0 (API 24) 及以上 + +7. **国际化**: 所有返回的文本信息已改为英文,中文保留在注释中 + +## 已修复的问题 + +### getOpenGLVersion() 返回 null +**问题**: 在某些设备上,`getOpenGLVersion()` 可能返回 `null` + +**原因**: EGL 上下文创建失败或 GL 字符串查询失败 + +**解决方案**: +1. 添加了回退机制:从 Vulkan 版本推断 OpenGL ES 支持 +2. 确保总是返回非 null 值(至少返回 "Unknown") +3. 增加了错误处理 + +## 扩展建议 + +如果需要添加更多 GPU 型号的支持,可以在 `getGpuSpecsByRenderer()` 方法中添加新的匹配规则: + +```kotlin +"your_gpu_name" in renderer -> GpuDetailedInfo( + maxFrequency = 850, // MHz + architecture = "Architecture Name", + cacheSize = 1024, // KB + bandwidth = 38.4, // GB/s + computeUnits = 5, + shadingUnits = 640 +) +``` + +## 性能分级参考 + +根据获取的 GPU 信息,可以进行性能分级: + +- **旗舰级**: 频率 > 800 MHz, 带宽 > 45 GB/s, 计算单元 >= 6 +- **高端**: 频率 > 650 MHz, 带宽 > 35 GB/s, 计算单元 >= 4 +- **中端**: 频率 > 500 MHz, 带宽 > 20 GB/s, 计算单元 >= 3 +- **入门级**: 其他 diff --git a/StorageInfo使用示例.md b/StorageInfo使用示例.md new file mode 100644 index 0000000..7947423 --- /dev/null +++ b/StorageInfo使用示例.md @@ -0,0 +1,671 @@ +# StorageInfo 存储空间详细信息使用示例 + +## 新增功能说明 + +`StorageInfo` 类已增强,新增以下功能: +- **Apps & Data 大小**: 应用程序和用户数据占用的存储空间 +- **System 大小**: 系统分区占用的存储空间 +- **Free 大小**: 可用的存储空间 +- **Cache 大小**: 缓存占用的存储空间 +- **存储分解信息**: 详细的存储空间使用情况分析 +- **存储摘要**: 格式化的完整存储信息 + +## 核心数据类 + +### StorageBreakdown +```kotlin +data class StorageBreakdown( + val totalSpace: Long, // 总空间(字节) + val usedSpace: Long, // 已使用空间(字节) + val freeSpace: Long, // 可用空间(字节) + val systemSize: Long, // 系统占用(字节) + val appsAndDataSize: Long, // 应用和数据占用(字节) + val cacheSize: Long, // 缓存占用(字节) + val otherSize: Long // 其他占用(字节) +) { + val usedPercentage: Double // 已使用百分比 + val freePercentage: Double // 可用百分比 +} +``` + +## 使用示例 + +### 1. 获取基本存储信息 + +```kotlin +val storageInfo = StorageInfo(context) + +// 直接访问属性获取大小 +val appsDataSize = storageInfo.applicationsAndDataSize +println("Apps & Data: ${storageInfo.formatBytes(appsDataSize)}") + +val systemSize = storageInfo.systemSize +println("System: ${storageInfo.formatBytes(systemSize)}") + +val freeSpace = storageInfo.internalStorageAvailableSpace +println("Free: ${storageInfo.formatBytes(freeSpace)}") + +val cacheSize = storageInfo.cacheSize +println("Cache: ${storageInfo.formatBytes(cacheSize)}") +``` + +输出示例: +``` +Apps & Data: 18.5 GB +System: 8.2 GB +Free: 32.1 GB +Cache: 1.2 GB +``` + +### 2. 获取格式化的存储信息 + +```kotlin +val storageInfo = StorageInfo(context) + +// 直接获取格式化的字符串 +val appsData = storageInfo.getFormattedAppsAndDataSize() +val system = storageInfo.getFormattedSystemSize() +val free = storageInfo.getFormattedFreeSpace() +val cache = storageInfo.getFormattedCacheSize() + +println("Apps & Data: $appsData") +println("System: $system") +println("Free: $free") +println("Cache: $cache") +``` + +### 3. 获取完整的存储分解信息 + +```kotlin +val storageInfo = StorageInfo(context) + +// 获取详细的存储分解 +val breakdown = storageInfo.getInternalStorageBreakdown() + +println("=== Storage Breakdown ===") +println("Total: ${storageInfo.formatBytes(breakdown.totalSpace)}") +println("Used: ${storageInfo.formatBytes(breakdown.usedSpace)} (${String.format("%.1f%%", breakdown.usedPercentage)})") +println("Free: ${storageInfo.formatBytes(breakdown.freeSpace)} (${String.format("%.1f%%", breakdown.freePercentage)})") +println() +println("Breakdown:") +println(" System: ${storageInfo.formatBytes(breakdown.systemSize)}") +println(" Apps & Data: ${storageInfo.formatBytes(breakdown.appsAndDataSize)}") +println(" Cache: ${storageInfo.formatBytes(breakdown.cacheSize)}") +println(" Other: ${storageInfo.formatBytes(breakdown.otherSize)}") +``` + +输出示例: +``` +=== Storage Breakdown === +Total: 128.00 GB +Used: 85.4 GB (66.7%) +Free: 42.6 GB (33.3%) + +Breakdown: + System: 8.2 GB + Apps & Data: 18.5 GB + Cache: 1.2 GB + Other: 57.5 GB +``` + +### 4. 获取存储使用百分比 + +```kotlin +val storageInfo = StorageInfo(context) + +// 获取使用百分比 +val usedPercentage = storageInfo.getUsagePercentage() +println("Storage Used: ${String.format("%.1f%%", usedPercentage)}") + +// 获取可用百分比 +val freePercentage = storageInfo.getFreePercentage() +println("Storage Free: ${String.format("%.1f%%", freePercentage)}") + +// 判断存储状态 +when { + usedPercentage > 90 -> println("Warning: Storage almost full!") + usedPercentage > 80 -> println("Storage is getting full") + usedPercentage > 50 -> println("Storage usage is moderate") + else -> println("Plenty of storage available") +} +``` + +### 5. 获取完整的存储摘要 + +```kotlin +val storageInfo = StorageInfo(context) + +// 获取格式化的完整摘要 +val summary = storageInfo.getStorageSummary() +println(summary) +``` + +输出示例: +``` +=== Internal Storage === +Total: 128.00 GB +Used: 85.4 GB (66.7%) +Free: 42.6 GB (33.3%) + +=== Storage Breakdown === +System: 8.2 GB +Apps & Data: 18.5 GB +Cache: 1.2 GB +Other: 57.5 GB + +=== External Storage === +Total: 256.00 GB +Used: 128.3 GB +Free: 127.7 GB +Emulated: Yes +Removable: No + +=== Storage Features === +Encrypted: Yes +Encryption Type: FBE +File System: ext4 + +=== Partition Scheme === +A/B Updates: Yes +Dynamic Partitions: Yes +Virtual A/B: Yes +``` + +### 6. 在 Jetpack Compose 中显示存储信息 + +```kotlin +@Composable +fun StorageInfoCard() { + val context = LocalContext.current + val storageInfo = remember { StorageInfo(context) } + val breakdown = remember { storageInfo.getInternalStorageBreakdown() } + + Card( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + elevation = CardDefaults.cardElevation(4.dp) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Text( + text = "Storage Information", + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold + ) + + Spacer(modifier = Modifier.height(16.dp)) + + // 存储使用进度条 + StorageProgressBar( + used = breakdown.usedSpace, + total = breakdown.totalSpace, + usedPercentage = breakdown.usedPercentage + ) + + Spacer(modifier = Modifier.height(16.dp)) + + // 总览 + InfoSection(title = "Overview") { + InfoRow( + "Total", + storageInfo.formatBytes(breakdown.totalSpace) + ) + InfoRow( + "Used", + "${storageInfo.formatBytes(breakdown.usedSpace)} (${String.format("%.1f%%", breakdown.usedPercentage)})" + ) + InfoRow( + "Free", + "${storageInfo.formatBytes(breakdown.freeSpace)} (${String.format("%.1f%%", breakdown.freePercentage)})" + ) + } + + Spacer(modifier = Modifier.height(12.dp)) + + // 详细分解 + InfoSection(title = "Breakdown") { + StorageBreakdownItem( + "System", + breakdown.systemSize, + breakdown.totalSpace, + Color(0xFF2196F3) + ) + StorageBreakdownItem( + "Apps & Data", + breakdown.appsAndDataSize, + breakdown.totalSpace, + Color(0xFF4CAF50) + ) + StorageBreakdownItem( + "Cache", + breakdown.cacheSize, + breakdown.totalSpace, + Color(0xFFFFC107) + ) + StorageBreakdownItem( + "Other", + breakdown.otherSize, + breakdown.totalSpace, + Color(0xFF9E9E9E) + ) + } + } + } +} + +@Composable +fun StorageProgressBar( + used: Long, + total: Long, + usedPercentage: Double +) { + Column { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = "Storage Usage", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Text( + text = String.format("%.1f%%", usedPercentage), + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + + LinearProgressIndicator( + progress = (usedPercentage / 100).toFloat(), + modifier = Modifier + .fillMaxWidth() + .height(8.dp) + .clip(RoundedCornerShape(4.dp)), + color = when { + usedPercentage > 90 -> Color(0xFFF44336) + usedPercentage > 80 -> Color(0xFFFF9800) + else -> Color(0xFF4CAF50) + } + ) + } +} + +@Composable +fun StorageBreakdownItem( + label: String, + size: Long, + total: Long, + color: Color +) { + val storageInfo = StorageInfo(LocalContext.current) + val percentage = if (total > 0) (size.toDouble() / total * 100) else 0.0 + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + Box( + modifier = Modifier + .size(12.dp) + .background(color, CircleShape) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = label, + style = MaterialTheme.typography.bodyMedium + ) + } + + Text( + text = "${storageInfo.formatBytes(size)} (${String.format("%.1f%%", percentage)})", + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium + ) + } +} + +@Composable +fun InfoSection(title: String, content: @Composable () -> Unit) { + Column { + Text( + text = title, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + color = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.height(8.dp)) + content() + } +} + +@Composable +fun InfoRow(label: String, value: String) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = label, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Text( + text = value, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium, + textAlign = TextAlign.End, + modifier = Modifier.weight(1f, fill = false) + ) + } +} +``` + +### 7. 存储空间监控 + +```kotlin +class StorageMonitor(private val context: Context) { + private val storageInfo = StorageInfo(context) + + /** + * 检查存储状态 + */ + fun checkStorageStatus(): StorageStatus { + val freeSpace = storageInfo.internalStorageAvailableSpace + val usedPercentage = storageInfo.getUsagePercentage() + + return when { + freeSpace < 1024 * 1024 * 1024 -> // < 1 GB + StorageStatus.CRITICAL + usedPercentage > 90 -> + StorageStatus.LOW + usedPercentage > 80 -> + StorageStatus.WARNING + else -> + StorageStatus.HEALTHY + } + } + + /** + * 获取存储建议 + */ + fun getStorageRecommendation(): String { + val status = checkStorageStatus() + val cacheSize = storageInfo.cacheSize + + return when (status) { + StorageStatus.CRITICAL -> { + "Critical: Storage almost full! Clear ${storageInfo.formatBytes(cacheSize)} cache immediately." + } + StorageStatus.LOW -> { + "Warning: Low storage space. Consider clearing cache or removing unused apps." + } + StorageStatus.WARNING -> { + "Storage is getting full. You may want to free up some space." + } + StorageStatus.HEALTHY -> { + "Storage is healthy. ${storageInfo.getFormattedFreeSpace()} available." + } + } + } + + enum class StorageStatus { + HEALTHY, WARNING, LOW, CRITICAL + } +} + +// 使用示例 +val monitor = StorageMonitor(context) +val status = monitor.checkStorageStatus() +val recommendation = monitor.getStorageRecommendation() + +println("Storage Status: $status") +println("Recommendation: $recommendation") +``` + +### 8. 计算可安装应用数量 + +```kotlin +fun estimateInstallableApps(context: Context): Int { + val storageInfo = StorageInfo(context) + val freeSpace = storageInfo.internalStorageAvailableSpace + + // 平均应用大小约 50 MB + val averageAppSize = 50 * 1024 * 1024L + + // 保留 2 GB 作为系统缓冲 + val reservedSpace = 2L * 1024 * 1024 * 1024 + val availableForApps = maxOf(0L, freeSpace - reservedSpace) + + return (availableForApps / averageAppSize).toInt() +} + +// 使用示例 +val estimatedApps = estimateInstallableApps(context) +println("You can install approximately $estimatedApps more apps") +``` + +### 9. 存储趋势分析 + +```kotlin +class StorageTrendAnalyzer(private val context: Context) { + private val storageInfo = StorageInfo(context) + private val prefs = context.getSharedPreferences("storage_trend", Context.MODE_PRIVATE) + + /** + * 记录当前存储使用情况 + */ + fun recordCurrentUsage() { + val used = storageInfo.internalStorageUsedSpace + val timestamp = System.currentTimeMillis() + + prefs.edit() + .putLong("last_used", used) + .putLong("last_timestamp", timestamp) + .apply() + } + + /** + * 计算每日平均增长 + */ + fun getDailyGrowth(): Long { + val currentUsed = storageInfo.internalStorageUsedSpace + val lastUsed = prefs.getLong("last_used", 0) + val lastTimestamp = prefs.getLong("last_timestamp", 0) + + if (lastUsed == 0L || lastTimestamp == 0L) { + return 0L + } + + val daysPassed = (System.currentTimeMillis() - lastTimestamp) / (24 * 60 * 60 * 1000) + if (daysPassed == 0L) return 0L + + val growth = currentUsed - lastUsed + return growth / daysPassed + } + + /** + * 预估空间耗尽时间 + */ + fun estimateDaysUntilFull(): Int { + val dailyGrowth = getDailyGrowth() + if (dailyGrowth <= 0) return Int.MAX_VALUE + + val freeSpace = storageInfo.internalStorageAvailableSpace + val reservedSpace = 1L * 1024 * 1024 * 1024 // 保留 1 GB + val usableSpace = maxOf(0L, freeSpace - reservedSpace) + + return (usableSpace / dailyGrowth).toInt() + } +} + +// 使用示例 +val analyzer = StorageTrendAnalyzer(context) +analyzer.recordCurrentUsage() + +val dailyGrowth = analyzer.getDailyGrowth() +val daysUntilFull = analyzer.estimateDaysUntilFull() + +println("Daily Growth: ${StorageInfo(context).formatBytes(dailyGrowth)}") +if (daysUntilFull < 365) { + println("Storage will be full in approximately $daysUntilFull days") +} +``` + +### 10. 比较不同类别的存储占用 + +```kotlin +fun compareStorageCategories(context: Context) { + val storageInfo = StorageInfo(context) + val breakdown = storageInfo.getInternalStorageBreakdown() + + data class CategoryInfo(val name: String, val size: Long) + + val categories = listOf( + CategoryInfo("System", breakdown.systemSize), + CategoryInfo("Apps & Data", breakdown.appsAndDataSize), + CategoryInfo("Cache", breakdown.cacheSize), + CategoryInfo("Other", breakdown.otherSize) + ) + + // 按大小排序 + val sorted = categories.sortedByDescending { it.size } + + println("=== Storage Usage by Category ===") + sorted.forEachIndexed { index, category -> + val percentage = (category.size.toDouble() / breakdown.totalSpace * 100) + val bar = "█".repeat((percentage / 2).toInt().coerceIn(0, 50)) + + println( + "${index + 1}. ${category.name.padEnd(15)} " + + "${storageInfo.formatBytes(category.size).padStart(10)} " + + "(${String.format("%5.1f%%", percentage)}) $bar" + ) + } + + // 找出占用最大的类别 + val largest = sorted.first() + println("\nLargest category: ${largest.name} (${storageInfo.formatBytes(largest.size)})") +} +``` + +输出示例: +``` +=== Storage Usage by Category === +1. Other 57.5 GB ( 44.9%) ██████████████████████ +2. Apps & Data 18.5 GB ( 14.5%) ███████ +3. System 8.2 GB ( 6.4%) ███ +4. Cache 1.2 GB ( 0.9%) + +Largest category: Other (57.5 GB) +``` + +## 技术细节 + +### 计算方法 + +1. **Apps & Data 大小**: + - 扫描 `/data/data` (应用数据) + - 扫描 `/data/app` (已安装应用) + - 递归计算目录大小 + +2. **System 大小**: + - 使用 `StatFs` 读取 `/system` 分区大小 + - 包括系统应用和核心文件 + +3. **Cache 大小**: + - 扫描 `/data/cache` (系统缓存) + - 包括应用缓存目录 + +4. **Free 大小**: + - 使用 `StatFs.availableBlocksLong` 获取可用块 + - 乘以块大小得到字节数 + +### 存储分类 + +- **System**: 操作系统和系统应用 +- **Apps & Data**: 用户安装的应用和数据 +- **Cache**: 临时文件和缓存 +- **Other**: 媒体文件、下载等其他内容 + +## 注意事项 + +1. **权限**: + - 基本存储信息无需特殊权限 + - 某些目录可能因权限限制无法访问 + +2. **性能**: + - 计算目录大小是耗时操作 + - 建议在后台线程执行 + - 考虑缓存结果 + +3. **精确度**: + - 由于权限限制,某些大小可能不完全精确 + - 系统文件和隐藏文件可能未计入 + +4. **存储单位**: + - 1 KB = 1024 bytes + - 1 MB = 1024 KB + - 1 GB = 1024 MB + +5. **兼容性**: + - 支持 Android 5.0 (API 21) 及以上 + - 某些特性需要更高 API 级别 + +## 性能优化建议 + +### 异步加载 + +```kotlin +// 在协程中加载 +lifecycleScope.launch(Dispatchers.IO) { + val storageInfo = StorageInfo(context) + val breakdown = storageInfo.getInternalStorageBreakdown() + + withContext(Dispatchers.Main) { + // 更新 UI + updateStorageUI(breakdown) + } +} +``` + +### 缓存结果 + +```kotlin +class CachedStorageInfo(context: Context) { + private val storageInfo = StorageInfo(context) + private var cachedBreakdown: StorageBreakdown? = null + private var lastUpdateTime: Long = 0 + + fun getBreakdown(forceRefresh: Boolean = false): StorageBreakdown { + val now = System.currentTimeMillis() + val cacheExpired = now - lastUpdateTime > 5 * 60 * 1000 // 5 分钟 + + if (cachedBreakdown == null || cacheExpired || forceRefresh) { + cachedBreakdown = storageInfo.getInternalStorageBreakdown() + lastUpdateTime = now + } + + return cachedBreakdown!! + } +} +``` + +## 常见应用场景 + +1. **存储管理应用**: 显示详细的存储使用情况 +2. **清理工具**: 识别可清理的缓存和临时文件 +3. **应用市场**: 检查是否有足够空间安装应用 +4. **备份工具**: 评估备份所需空间 +5. **文件管理器**: 提供存储概览 +6. **设置应用**: 显示系统存储信息 +7. **性能监控**: 跟踪存储趋势 +8. **用户提醒**: 低存储空间警告 diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CameraInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CameraInfo.kt index 685dea8..27f5da1 100644 --- a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CameraInfo.kt +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CameraInfo.kt @@ -163,10 +163,10 @@ class CameraInfo(private val context: Context) { */ fun getCameraFacingText(characteristics: CameraCharacteristics): String { return when (getCameraFacing(characteristics)) { - CameraFacing.BACK -> "后置" - CameraFacing.FRONT -> "前置" - CameraFacing.EXTERNAL -> "外置" - else -> "未知" + CameraFacing.BACK -> "Back" // 后置 + CameraFacing.FRONT -> "Front" // 前置 + CameraFacing.EXTERNAL -> "External" // 外置 + else -> "Unknown" // 未知 } } @@ -233,8 +233,8 @@ class CameraInfo(private val context: Context) { CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG -> "GBRG (Bayer)" CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR -> "BGGR (Bayer)" CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB -> "RGB" - 5 -> "Mono/NIR (单色/近红外)" // MONO/NIR - else -> "未知" + 5 -> "Mono/NIR" // 单色/近红外 + else -> "Unknown" // 未知 } } } @@ -409,8 +409,8 @@ class CameraInfo(private val context: Context) { CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL -> "FULL" CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY -> "LEGACY" CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 -> "LEVEL_3" - CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "EXTERNAL" else "未知" - else -> "未知" + CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "EXTERNAL" else "Unknown" // 未知 + else -> "Unknown" // 未知 } } } @@ -430,10 +430,10 @@ class CameraInfo(private val context: Context) { fun getFaceDetectionModes(characteristics: CameraCharacteristics): List? { return characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES)?.map { when (it) { - CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_OFF -> "关闭" - CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE -> "简单" - CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_FULL -> "完整" - else -> "未知" + CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_OFF -> "Off" // 关闭 + CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE -> "Simple" // 简单 + CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_FULL -> "Full" // 完整 + else -> "Unknown" // 未知 } } } @@ -480,17 +480,17 @@ class CameraInfo(private val context: Context) { val features = mutableListOf() val capabilities = getAvailableCapabilities(characteristics) - if (capabilities.contains(CameraCapability.RAW)) features.add("RAW拍摄") - if (capabilities.contains(CameraCapability.BURST_CAPTURE)) features.add("连拍") - if (capabilities.contains(CameraCapability.DEPTH_OUTPUT)) features.add("景深输出") - if (capabilities.contains(CameraCapability.CONSTRAINED_HIGH_SPEED_VIDEO)) features.add("高速视频") - if (capabilities.contains(CameraCapability.MANUAL_SENSOR)) features.add("手动模式") - if (capabilities.contains(CameraCapability.MONOCHROME)) features.add("黑白模式") - if (capabilities.contains(CameraCapability.ULTRA_HIGH_RESOLUTION_SENSOR)) features.add("超高分辨率") + if (capabilities.contains(CameraCapability.RAW)) features.add("RAW Capture") // RAW拍摄 + if (capabilities.contains(CameraCapability.BURST_CAPTURE)) features.add("Burst Capture") // 连拍 + if (capabilities.contains(CameraCapability.DEPTH_OUTPUT)) features.add("Depth Output") // 景深输出 + if (capabilities.contains(CameraCapability.CONSTRAINED_HIGH_SPEED_VIDEO)) features.add("High Speed Video") // 高速视频 + if (capabilities.contains(CameraCapability.MANUAL_SENSOR)) features.add("Manual Mode") // 手动模式 + if (capabilities.contains(CameraCapability.MONOCHROME)) features.add("Monochrome Mode") // 黑白模式 + if (capabilities.contains(CameraCapability.ULTRA_HIGH_RESOLUTION_SENSOR)) features.add("Ultra High Resolution") // 超高分辨率 if (capabilities.contains(CameraCapability.DYNAMIC_RANGE_TEN_BIT)) features.add("10-bit HDR") - if (hasOpticalStabilization(characteristics)) features.add("光学防抖") - if (hasVideoStabilization(characteristics)) features.add("视频防抖") + if (hasOpticalStabilization(characteristics)) features.add("Optical Stabilization") // 光学防抖 + if (hasVideoStabilization(characteristics)) features.add("Video Stabilization") // 视频防抖 return features } @@ -503,13 +503,13 @@ class CameraInfo(private val context: Context) { fun getAutoExposureModes(characteristics: CameraCharacteristics): List? { return characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES)?.map { when (it) { - CameraCharacteristics.CONTROL_AE_MODE_OFF -> "关闭" - CameraCharacteristics.CONTROL_AE_MODE_ON -> "自动" - CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH -> "自动闪光" - CameraCharacteristics.CONTROL_AE_MODE_ON_ALWAYS_FLASH -> "强制闪光" - CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE -> "防红眼" - CameraCharacteristics.CONTROL_AE_MODE_ON_EXTERNAL_FLASH -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "外置闪光" else "未知" - else -> "未知" + CameraCharacteristics.CONTROL_AE_MODE_OFF -> "Off" // 关闭 + CameraCharacteristics.CONTROL_AE_MODE_ON -> "Auto" // 自动 + CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH -> "Auto Flash" // 自动闪光 + CameraCharacteristics.CONTROL_AE_MODE_ON_ALWAYS_FLASH -> "Always Flash" // 强制闪光 + CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE -> "Auto Flash Redeye" // 防红眼 + CameraCharacteristics.CONTROL_AE_MODE_ON_EXTERNAL_FLASH -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "External Flash" else "Unknown" // 外置闪光/未知 + else -> "Unknown" // 未知 } } } @@ -520,13 +520,13 @@ class CameraInfo(private val context: Context) { fun getAutoFocusModes(characteristics: CameraCharacteristics): List? { return characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES)?.map { when (it) { - CameraCharacteristics.CONTROL_AF_MODE_OFF -> "关闭" - CameraCharacteristics.CONTROL_AF_MODE_AUTO -> "自动" - CameraCharacteristics.CONTROL_AF_MODE_MACRO -> "微距" - CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_VIDEO -> "连续视频" - CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_PICTURE -> "连续拍照" + CameraCharacteristics.CONTROL_AF_MODE_OFF -> "Off" // 关闭 + CameraCharacteristics.CONTROL_AF_MODE_AUTO -> "Auto" // 自动 + CameraCharacteristics.CONTROL_AF_MODE_MACRO -> "Macro" // 微距 + CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_VIDEO -> "Continuous Video" // 连续视频 + CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_PICTURE -> "Continuous Picture" // 连续拍照 CameraCharacteristics.CONTROL_AF_MODE_EDOF -> "EDOF" - else -> "未知" + else -> "Unknown" // 未知 } } } @@ -537,16 +537,16 @@ class CameraInfo(private val context: Context) { fun getWhiteBalanceModes(characteristics: CameraCharacteristics): List? { return characteristics.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES)?.map { when (it) { - CameraCharacteristics.CONTROL_AWB_MODE_OFF -> "关闭" - CameraCharacteristics.CONTROL_AWB_MODE_AUTO -> "自动" - CameraCharacteristics.CONTROL_AWB_MODE_INCANDESCENT -> "白炽灯" - CameraCharacteristics.CONTROL_AWB_MODE_FLUORESCENT -> "荧光灯" - CameraCharacteristics.CONTROL_AWB_MODE_WARM_FLUORESCENT -> "暖荧光" - CameraCharacteristics.CONTROL_AWB_MODE_DAYLIGHT -> "日光" - CameraCharacteristics.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT -> "阴天" - CameraCharacteristics.CONTROL_AWB_MODE_TWILIGHT -> "黄昏" - CameraCharacteristics.CONTROL_AWB_MODE_SHADE -> "阴影" - else -> "未知" + CameraCharacteristics.CONTROL_AWB_MODE_OFF -> "Off" // 关闭 + CameraCharacteristics.CONTROL_AWB_MODE_AUTO -> "Auto" // 自动 + CameraCharacteristics.CONTROL_AWB_MODE_INCANDESCENT -> "Incandescent" // 白炽灯 + CameraCharacteristics.CONTROL_AWB_MODE_FLUORESCENT -> "Fluorescent" // 荧光灯 + CameraCharacteristics.CONTROL_AWB_MODE_WARM_FLUORESCENT -> "Warm Fluorescent" // 暖荧光 + CameraCharacteristics.CONTROL_AWB_MODE_DAYLIGHT -> "Daylight" // 日光 + CameraCharacteristics.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT -> "Cloudy" // 阴天 + CameraCharacteristics.CONTROL_AWB_MODE_TWILIGHT -> "Twilight" // 黄昏 + CameraCharacteristics.CONTROL_AWB_MODE_SHADE -> "Shade" // 阴影 + else -> "Unknown" // 未知 } } } @@ -557,26 +557,26 @@ class CameraInfo(private val context: Context) { fun getSceneModes(characteristics: CameraCharacteristics): List? { return characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES)?.map { when (it) { - CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED -> "禁用" - CameraCharacteristics.CONTROL_SCENE_MODE_FACE_PRIORITY -> "人像优先" - CameraCharacteristics.CONTROL_SCENE_MODE_ACTION -> "运动" - CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT -> "人像" - CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE -> "风景" - CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT -> "夜景" - CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT -> "夜景人像" - CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE -> "剧院" - CameraCharacteristics.CONTROL_SCENE_MODE_BEACH -> "海滩" - CameraCharacteristics.CONTROL_SCENE_MODE_SNOW -> "雪景" - CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET -> "日落" - CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO -> "防抖" - CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS -> "烟火" - CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS -> "体育" - CameraCharacteristics.CONTROL_SCENE_MODE_PARTY -> "派对" - CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT -> "烛光" - CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE -> "条形码" - CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) "高速视频" else "未知" + CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED -> "Disabled" // 禁用 + CameraCharacteristics.CONTROL_SCENE_MODE_FACE_PRIORITY -> "Face Priority" // 人像优先 + CameraCharacteristics.CONTROL_SCENE_MODE_ACTION -> "Action" // 运动 + CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT -> "Portrait" // 人像 + CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE -> "Landscape" // 风景 + CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT -> "Night" // 夜景 + CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT -> "Night Portrait" // 夜景人像 + CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE -> "Theatre" // 剧院 + CameraCharacteristics.CONTROL_SCENE_MODE_BEACH -> "Beach" // 海滩 + CameraCharacteristics.CONTROL_SCENE_MODE_SNOW -> "Snow" // 雪景 + CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET -> "Sunset" // 日落 + CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO -> "Steady Photo" // 防抖 + CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS -> "Fireworks" // 烟火 + CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS -> "Sports" // 体育 + CameraCharacteristics.CONTROL_SCENE_MODE_PARTY -> "Party" // 派对 + CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT -> "Candlelight" // 烛光 + CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE -> "Barcode" // 条形码 + CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) "High Speed Video" else "Unknown" // 高速视频/未知 CameraCharacteristics.CONTROL_SCENE_MODE_HDR -> "HDR" - else -> "未知" + else -> "Unknown" // 未知 } } } @@ -587,16 +587,16 @@ class CameraInfo(private val context: Context) { fun getColorEffects(characteristics: CameraCharacteristics): List? { return characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS)?.map { when (it) { - CameraCharacteristics.CONTROL_EFFECT_MODE_OFF -> "关闭" - CameraCharacteristics.CONTROL_EFFECT_MODE_MONO -> "黑白" - CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE -> "负片" - CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE -> "曝光" - CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA -> "棕褐色" - CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE -> "海报化" - CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD -> "白板" - CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD -> "黑板" - CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA -> "水蓝" - else -> "未知" + CameraCharacteristics.CONTROL_EFFECT_MODE_OFF -> "Off" // 关闭 + CameraCharacteristics.CONTROL_EFFECT_MODE_MONO -> "Mono" // 黑白 + CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE -> "Negative" // 负片 + CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE -> "Solarize" // 曝光 + CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA -> "Sepia" // 棕褐色 + CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE -> "Posterize" // 海报化 + CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD -> "Whiteboard" // 白板 + CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD -> "Blackboard" // 黑板 + CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA -> "Aqua" // 水蓝 + else -> "Unknown" // 未知 } } } diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CpuInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CpuInfo.kt index 3204cc4..5617d9c 100644 --- a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CpuInfo.kt +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/CpuInfo.kt @@ -32,6 +32,63 @@ class CpuInfo { val cores: List get() = CpuInfoUtils.getCores() + /** + * 增强的核心信息数据类 + * 包含核心的基本信息以及实时频率和性能度量 + * @property core 核心基本信息 + * @property currentFrequency 当前频率(Hz) + * @property minFrequency 最小频率(Hz) + * @property maxFrequency 最大频率(Hz) + * @property availableFrequencies 可用频率列表(Hz) + * @property speedMetric 速度度量值 + */ + data class CoreDetailedInfo( + val core: Core, + val currentFrequency: Long, + val minFrequency: Long, + val maxFrequency: Long, + val availableFrequencies: List, + val speedMetric: Double + ) + + /** + * 获取所有核心的详细信息(包含频率和速度度量) + * @return 详细核心信息列表 + */ + fun getCoresDetailedInfo(): List { + val coresList = cores + val result = mutableListOf() + + coresList.forEachIndexed { index, core -> + val currentFreq = readFrequency("/sys/devices/system/cpu/cpu$index/cpufreq/scaling_cur_freq") * 1000 // Convert KHz to Hz + val minFreq = readFrequency("/sys/devices/system/cpu/cpu$index/cpufreq/cpuinfo_min_freq") * 1000 + val maxFreq = readFrequency("/sys/devices/system/cpu/cpu$index/cpufreq/cpuinfo_max_freq") * 1000 + val availableFreqs = readAvailableFrequencies("/sys/devices/system/cpu/cpu$index/cpufreq/scaling_available_frequencies") + .map { it * 1000 } // Convert KHz to Hz + + // Calculate speed metric for this core + // Speed metric = (current_freq / max_freq) * 100, or use max_freq as baseline + val speedMetric = if (maxFreq > 0) { + (maxFreq.toDouble() / 1_000_000_000.0) // Convert to GHz as metric + } else { + 0.0 + } + + result.add( + CoreDetailedInfo( + core = core, + currentFrequency = currentFreq, + minFrequency = minFreq, + maxFrequency = maxFreq, + availableFrequencies = availableFreqs, + speedMetric = speedMetric + ) + ) + } + + return result + } + /** * 获取所有核心集群列表(大小核分组) * @return 集群列表 @@ -100,7 +157,7 @@ class CpuInfo { return if (packages.isNotEmpty()) { packages[0].name } else { - "未知" + "Unknown" // 未知 } } @@ -112,7 +169,7 @@ class CpuInfo { return if (cores.isNotEmpty()) { cores[0].vendor.name } else { - "未知" + "Unknown" // 未知 } } @@ -205,7 +262,7 @@ class CpuInfo { /** * 制程信息数据类 * @property process 制程工艺,例如 "4nm", "5nm", "7nm" 等 - * @property foundry 代工厂,例如 "台积电", "三星" 等 + * @property foundry 代工厂,例如 "TSMC", "Samsung" 等 * @property node 详细制程节点,例如 "TSMC N4P", "Samsung 4LPE" 等 */ data class ProcessInfo( @@ -224,110 +281,110 @@ class CpuInfo { return when { // 高通 Snapdragon 8 系列 "snapdragon 8 gen 3" in processorName || "sm8650" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4P") + ProcessInfo("4nm", "TSMC", "TSMC N4P") // 台积电 "snapdragon 8 gen 2" in processorName || "sm8550" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 "snapdragon 8 gen 1" in processorName || "sm8450" in processorName -> - ProcessInfo("4nm", "三星", "Samsung 4LPE") + ProcessInfo("4nm", "Samsung", "Samsung 4LPE") // 三星 "snapdragon 888+" in processorName || "sm8350-ab" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 "snapdragon 888" in processorName || "sm8350" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 "snapdragon 870" in processorName || "sm8250-ac" in processorName -> - ProcessInfo("7nm", "台积电", "TSMC N7P") + ProcessInfo("7nm", "TSMC", "TSMC N7P") // 台积电 "snapdragon 865+" in processorName || "sm8250-ab" in processorName -> - ProcessInfo("7nm", "台积电", "TSMC N7P") + ProcessInfo("7nm", "TSMC", "TSMC N7P") // 台积电 "snapdragon 865" in processorName || "sm8250" in processorName -> - ProcessInfo("7nm", "台积电", "TSMC N7P") + ProcessInfo("7nm", "TSMC", "TSMC N7P") // 台积电 // 高通 Snapdragon 7 系列 "snapdragon 7+ gen 2" in processorName || "sm7475" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 "snapdragon 778g" in processorName || "sm7325" in processorName -> - ProcessInfo("6nm", "台积电", "TSMC N6") + ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电 // 高通 Snapdragon 6 系列 "snapdragon 695" in processorName || "sm6375" in processorName -> - ProcessInfo("6nm", "台积电", "TSMC N6") + ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电 // 联发科 Dimensity 9000 系列 "dimensity 9300" in processorName || "mt6989" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4P") + ProcessInfo("4nm", "TSMC", "TSMC N4P") // 台积电 "dimensity 9200+" in processorName || "mt6985" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 "dimensity 9200" in processorName || "mt6983" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 "dimensity 9000+" in processorName || "mt6985" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 "dimensity 9000" in processorName || "mt6983" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 // 联发科 Dimensity 8000 系列 "dimensity 8300" in processorName || "mt6897" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 "dimensity 8200" in processorName || "mt6896" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 "dimensity 8100" in processorName || "mt6895" in processorName -> - ProcessInfo("5nm", "台积电", "TSMC N5") + ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电 // 联发科 Dimensity 1000 系列 "dimensity 1200" in processorName || "mt6893" in processorName -> - ProcessInfo("6nm", "台积电", "TSMC N6") + ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电 "dimensity 1080" in processorName || "mt6877" in processorName -> - ProcessInfo("6nm", "台积电", "TSMC N6") + ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电 // 联发科 Helio 系列 "helio g99" in processorName || "mt6789" in processorName -> - ProcessInfo("6nm", "台积电", "TSMC N6") + ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电 // 三星 Exynos "exynos 2400" in processorName || "s5e9945" in processorName -> - ProcessInfo("4nm", "三星", "Samsung 4LPP+") + ProcessInfo("4nm", "Samsung", "Samsung 4LPP+") // 三星 "exynos 2200" in processorName || "s5e9925" in processorName -> - ProcessInfo("4nm", "三星", "Samsung 4LPE") + ProcessInfo("4nm", "Samsung", "Samsung 4LPE") // 三星 "exynos 2100" in processorName || "s5e9840" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 "exynos 1080" in processorName || "s5e1080" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 "exynos 1380" in processorName || "s5e8835" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 "exynos 1280" in processorName || "s5e8825" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 // 谷歌 Tensor "tensor g3" in processorName || "gs301" in processorName -> - ProcessInfo("4nm", "三星", "Samsung 4LPP+") + ProcessInfo("4nm", "Samsung", "Samsung 4LPP+") // 三星 "tensor g2" in processorName || "gs201" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 "tensor g1" in processorName || "gs101" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 "tensor" in processorName -> - ProcessInfo("5nm", "三星", "Samsung 5LPE") + ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星 // 华为麒麟 "kirin 9000" in processorName -> - ProcessInfo("5nm", "台积电", "TSMC N5") + ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电 "kirin 9000e" in processorName -> - ProcessInfo("5nm", "台积电", "TSMC N5") + ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电 "kirin 990" in processorName -> - ProcessInfo("7nm", "台积电", "TSMC N7+") + ProcessInfo("7nm", "TSMC", "TSMC N7+") // 台积电 "kirin 980" in processorName -> - ProcessInfo("7nm", "台积电", "TSMC N7") + ProcessInfo("7nm", "TSMC", "TSMC N7") // 台积电 "kirin 810" in processorName -> - ProcessInfo("7nm", "台积电", "TSMC N7") + ProcessInfo("7nm", "TSMC", "TSMC N7") // 台积电 // 苹果 A 系列(参考) "apple a17" in processorName -> - ProcessInfo("3nm", "台积电", "TSMC N3B") + ProcessInfo("3nm", "TSMC", "TSMC N3B") // 台积电 "apple a16" in processorName -> - ProcessInfo("4nm", "台积电", "TSMC N4") + ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电 "apple a15" in processorName -> - ProcessInfo("5nm", "台积电", "TSMC N5P") + ProcessInfo("5nm", "TSMC", "TSMC N5P") // 台积电 "apple a14" in processorName -> - ProcessInfo("5nm", "台积电", "TSMC N5") + ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电 // 默认情况 - else -> ProcessInfo("未知", "未知", "") + else -> ProcessInfo("Unknown", "Unknown", "") // 未知 } } @@ -363,7 +420,7 @@ class CpuInfo { return if (cores.isNotEmpty()) { cores[0].uarch.name } else { - "未知" + "Unknown" // 未知 } } @@ -382,7 +439,7 @@ class CpuInfo { * @return ABI 字符串,例如 "arm64-v8a", "armeabi-v7a" 等 */ fun getAbi(): String { - return Build.SUPPORTED_ABIS.firstOrNull() ?: "未知" + return Build.SUPPORTED_ABIS.firstOrNull() ?: "Unknown" // 未知 } /** @@ -458,6 +515,218 @@ class CpuInfo { } } + /** + * 获取指定核心的最大频率 + * @param coreId 核心 ID + * @return 最大频率(KHz),失败返回 0 + */ + fun getMaxFrequency(coreId: Int): Long { + return readFrequency("/sys/devices/system/cpu/cpu$coreId/cpufreq/cpuinfo_max_freq") + } + + /** + * 获取指定核心的最小频率 + * @param coreId 核心 ID + * @return 最小频率(KHz),失败返回 0 + */ + fun getMinFrequency(coreId: Int): Long { + return readFrequency("/sys/devices/system/cpu/cpu$coreId/cpufreq/cpuinfo_min_freq") + } + + /** + * 获取指定核心的当前频率 + * @param coreId 核心 ID + * @return 当前频率(KHz),失败返回 0 + */ + fun getCurrentFrequency(coreId: Int): Long { + return readFrequency("/sys/devices/system/cpu/cpu$coreId/cpufreq/scaling_cur_freq") + } + + /** + * 获取所有核心的最大频率列表 + * @return 最大频率列表(KHz) + */ + fun getAllMaxFrequencies(): List { + return (0 until getCoreCount()).map { getMaxFrequency(it) } + } + + /** + * 获取所有核心的最小频率列表 + * @return 最小频率列表(KHz) + */ + fun getAllMinFrequencies(): List { + return (0 until getCoreCount()).map { getMinFrequency(it) } + } + + /** + * 获取所有核心的当前频率列表 + * @return 当前频率列表(KHz) + */ + fun getAllCurrentFrequencies(): List { + return (0 until getCoreCount()).map { getCurrentFrequency(it) } + } + + /** + * 获取系统中所有核心的最高最大频率 + * @return 最高频率(KHz) + */ + fun getSystemMaxFrequency(): Long { + return getAllMaxFrequencies().maxOrNull() ?: 0L + } + + /** + * 获取系统中所有核心的最低最小频率 + * @return 最低频率(KHz) + */ + fun getSystemMinFrequency(): Long { + return getAllMinFrequencies().minOrNull() ?: 0L + } + + // ==================== CPU 速度度量 ==================== + + /** + * 从 /proc/cpuinfo 读取 BogoMIPS 值 + * BogoMIPS 是 Linux 内核在启动时计算的 CPU 性能度量值 + * @return BogoMIPS 值,如果无法读取则返回 null + */ + fun getBogoMips(): Double? { + return try { + File("/proc/cpuinfo").readLines() + .find { it.startsWith("BogoMIPS") } + ?.substringAfter(":") + ?.trim() + ?.toDoubleOrNull() + } catch (e: Exception) { + null + } + } + + /** + * 获取所有核心的 BogoMIPS 值列表 + * @return BogoMIPS 列表 + */ + fun getAllBogoMips(): List { + return try { + File("/proc/cpuinfo").readLines() + .filter { it.startsWith("BogoMIPS") } + .mapNotNull { line -> + line.substringAfter(":") + .trim() + .toDoubleOrNull() + } + } catch (e: Exception) { + emptyList() + } + } + + /** + * CPU 速度度量数据类 + * @property totalScore 总体性能评分(基于频率和核心数计算) + * @property maxFrequency 系统最高频率(KHz) + * @property avgMaxFrequency 所有核心最大频率的平均值(KHz) + * @property bogoMips BogoMIPS 值(如果可用) + * @property performanceIndex 性能指数(0-100) + */ + data class CpuSpeedMetric( + val totalScore: Double, + val maxFrequency: Long, + val avgMaxFrequency: Double, + val bogoMips: Double?, + val performanceIndex: Double + ) + + /** + * 获取 CPU 速度度量值 + * 综合考虑核心数、频率、大小核配置等因素计算性能评分 + * @return CPU 速度度量对象 + */ + fun getCpuSpeedMetric(): CpuSpeedMetric { + val maxFreqs = getAllMaxFrequencies() + val systemMaxFreq = maxFreqs.maxOrNull() ?: 0L + val avgMaxFreq = if (maxFreqs.isNotEmpty()) { + maxFreqs.average() + } else { + 0.0 + } + + // 计算总体评分(基于频率和核心数) + // 公式:(平均最大频率 * 核心数) / 1000000,归一化到合理范围 + val totalScore = (avgMaxFreq * getCoreCount()) / 1000.0 + + // 获取 BogoMIPS + val bogoMips = getBogoMips() + + // 计算性能指数(0-100) + // 基准:8核心 @ 3.0GHz = 100分 + val baselineScore = 8.0 * 3_000_000 / 1000.0 // 24000 + val performanceIndex = ((totalScore / baselineScore) * 100).coerceIn(0.0, 150.0) + + return CpuSpeedMetric( + totalScore = totalScore, + maxFrequency = systemMaxFreq, + avgMaxFrequency = avgMaxFreq, + bogoMips = bogoMips, + performanceIndex = performanceIndex + ) + } + + /** + * 获取 CPU 性能等级评估 + * @return 性能等级描述(旗舰级、高端、中端、入门级) + */ + fun getCpuPerformanceLevel(): String { + val metric = getCpuSpeedMetric() + return when { + metric.performanceIndex >= 90 -> "Flagship" // 旗舰级 + metric.performanceIndex >= 70 -> "High-end" // 高端 + metric.performanceIndex >= 50 -> "Mid-range" // 中端 + metric.performanceIndex >= 30 -> "Entry-level" // 入门级 + else -> "Low-end" // 低端 + } + } + + /** + * 获取指定核心的详细信息 + * @param coreIndex 核心索引(从0开始) + * @return 详细核心信息,如果索引无效则返回 null + */ + fun getCoreDetailedInfo(coreIndex: Int): CoreDetailedInfo? { + if (coreIndex < 0 || coreIndex >= cores.size) return null + return getCoresDetailedInfo().getOrNull(coreIndex) + } + + /** + * 获取所有核心的最大频率列表(实时从系统读取) + * @return 最大频率列表(Hz) + */ + fun getCoresMaxFrequencies(): List { + return getCoresDetailedInfo().map { it.maxFrequency } + } + + /** + * 获取所有核心的最小频率列表(实时从系统读取) + * @return 最小频率列表(Hz) + */ + fun getCoresMinFrequencies(): List { + return getCoresDetailedInfo().map { it.minFrequency } + } + + /** + * 获取所有核心的当前频率列表(实时从系统读取) + * @return 当前频率列表(Hz) + */ + fun getCoresCurrentFrequencies(): List { + return getCoresDetailedInfo().map { it.currentFrequency } + } + + /** + * 获取所有核心的速度度量值列表 + * @return 速度度量值列表(GHz) + */ + fun getCoresSpeedMetrics(): List { + return getCoresDetailedInfo().map { it.speedMetric } + } + // ==================== 调频器信息 ==================== /** @@ -470,7 +739,7 @@ class CpuInfo { File("/sys/devices/system/cpu/cpu$coreId/cpufreq/scaling_governor") .readText().trim() } catch (e: Exception) { - "未知" + "Unknown" // 未知 } } @@ -525,7 +794,7 @@ class CpuInfo { return try { File("/proc/cpuinfo").readText() } catch (e: Exception) { - "无法读取 /proc/cpuinfo" + "Unable to read /proc/cpuinfo" // 无法读取 /proc/cpuinfo } } @@ -569,60 +838,74 @@ class CpuInfo { val sb = StringBuilder() // 基本信息 - sb.append("=== CPU 基本信息 ===\n") - sb.append("处理器名称: ${getProcessorName()}\n") - sb.append("供应商: ${getVendor()}\n") + sb.append("=== CPU Basic Info ===\n") // CPU 基本信息 + sb.append("Processor Name: ${getProcessorName()}\n") // 处理器名称 + sb.append("Vendor: ${getVendor()}\n") // 供应商 val processInfo = getProcessInfo() - sb.append("制程工艺: ${processInfo.process}\n") - sb.append("代工厂: ${processInfo.foundry}\n") + sb.append("Process: ${processInfo.process}\n") // 制程工艺 + sb.append("Foundry: ${processInfo.foundry}\n") // 代工厂 if (processInfo.node.isNotEmpty()) { - sb.append("制程节点: ${processInfo.node}\n") + sb.append("Process Node: ${processInfo.node}\n") // 制程节点 } - sb.append("物理核心数: ${getCoreCount()}\n") - sb.append("逻辑处理器数: ${getProcessorCount()}\n") + sb.append("Physical Cores: ${getCoreCount()}\n") // 物理核心数 + sb.append("Logical Processors: ${getProcessorCount()}\n") // 逻辑处理器数 // 大小核信息 val clusterInfo = getClusterInfo() - sb.append("\n=== 大小核配置 ===\n") + sb.append("\n=== Core Cluster Configuration ===\n") // 大小核配置 if (clusterInfo.bigCoreCount > 0) { - sb.append("大核: ${clusterInfo.bigCoreCount} 个, 最高频率: ${formatFrequency(clusterInfo.bigCoreFreq)}\n") + sb.append("Big Cores: ${clusterInfo.bigCoreCount}, Max Frequency: ${formatFrequency(clusterInfo.bigCoreFreq)}\n") // 大核 } if (clusterInfo.midCoreCount > 0) { - sb.append("中核: ${clusterInfo.midCoreCount} 个, 最高频率: ${formatFrequency(clusterInfo.midCoreFreq)}\n") + sb.append("Mid Cores: ${clusterInfo.midCoreCount}, Max Frequency: ${formatFrequency(clusterInfo.midCoreFreq)}\n") // 中核 } if (clusterInfo.littleCoreCount > 0) { - sb.append("小核: ${clusterInfo.littleCoreCount} 个, 最高频率: ${formatFrequency(clusterInfo.littleCoreFreq)}\n") + sb.append("Little Cores: ${clusterInfo.littleCoreCount}, Max Frequency: ${formatFrequency(clusterInfo.littleCoreFreq)}\n") // 小核 } // 架构信息 - sb.append("\n=== 架构信息 ===\n") - sb.append("架构: ${getAllArchitectures().joinToString(", ")}\n") + sb.append("\n=== Architecture Info ===\n") // 架构信息 + sb.append("Architecture: ${getAllArchitectures().joinToString(", ")}\n") // 架构 sb.append("ABI: ${getAbi()}\n") - sb.append("支持的 ABI: ${getSupportedAbis().joinToString(", ")}\n") + sb.append("Supported ABIs: ${getSupportedAbis().joinToString(", ")}\n") // 支持的 ABI + + // CPU 性能评估 + val speedMetric = getCpuSpeedMetric() + sb.append("\n=== Performance Metrics ===\n") // 性能指标 + sb.append("Performance Level: ${getCpuPerformanceLevel()}\n") // 性能等级 + sb.append("Performance Index: ${String.format("%.1f", speedMetric.performanceIndex)}\n") // 性能指数 + sb.append("Total Score: ${String.format("%.1f", speedMetric.totalScore)}\n") // 总体评分 + speedMetric.bogoMips?.let { + sb.append("BogoMIPS: ${String.format("%.2f", it)}\n") + } // 调频器 - sb.append("\n=== 调频器 ===\n") - sb.append("当前调频器: ${getGovernor(0)}\n") - sb.append("可用调频器: ${getAvailableGovernors().joinToString(", ")}\n") + sb.append("\n=== Governor ===\n") // 调频器 + sb.append("Current Governor: ${getGovernor(0)}\n") // 当前调频器 + sb.append("Available Governors: ${getAvailableGovernors().joinToString(", ")}\n") // 可用调频器 - // 核心详细频率 - sb.append("\n=== 核心频率信息 ===\n") - getCoreFrequencies().forEach { freq -> - sb.append("CPU${freq.coreId}: 当前=${formatFrequency(freq.currentFreq.toULong() * 1000UL)}, ") - sb.append("范围=${formatFrequency(freq.minFreq.toULong() * 1000UL)}-${formatFrequency(freq.maxFreq.toULong() * 1000UL)}\n") + // 核心详细信息(包含实时频率和速度度量) + sb.append("\n=== Core Detailed Info ===\n") // 核心详细信息 + val detailedCores = getCoresDetailedInfo() + detailedCores.forEachIndexed { index, coreInfo -> + sb.append("CPU$index: ") + sb.append("Current=${formatFrequency(coreInfo.currentFrequency.toULong())}, ") // 当前 + sb.append("Range=${formatFrequency(coreInfo.minFrequency.toULong())}-${formatFrequency(coreInfo.maxFrequency.toULong())}, ") // 范围 + sb.append("Metric=${String.format("%.2f GHz", coreInfo.speedMetric)}, ") // 度量值 + sb.append("Arch=${coreInfo.core.uarch.name}\n") // 架构 } // 缓存信息 - sb.append("\n=== 缓存信息 ===\n") - sb.append("L1i 缓存: ${l1iCaches.size} 个\n") - sb.append("L1d 缓存: ${l1dCaches.size} 个\n") - sb.append("L2 缓存: ${l2Caches.size} 个\n") - sb.append("L3 缓存: ${l3Caches.size} 个\n") + sb.append("\n=== Cache Info ===\n") // 缓存信息 + sb.append("L1i Cache: ${l1iCaches.size}\n") // L1i 缓存 + sb.append("L1d Cache: ${l1dCaches.size}\n") // L1d 缓存 + sb.append("L2 Cache: ${l2Caches.size}\n") // L2 缓存 + sb.append("L3 Cache: ${l3Caches.size}\n") // L3 缓存 // CPU 特性 val features = getCpuFeatures() if (features.isNotEmpty()) { - sb.append("\n=== CPU 特性 ===\n") + sb.append("\n=== CPU Features ===\n") // CPU 特性 sb.append(features.joinToString(" ")) sb.append("\n") } diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DisplayInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DisplayInfo.kt index 5bf26f6..ee02850 100644 --- a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DisplayInfo.kt +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/DisplayInfo.kt @@ -55,6 +55,14 @@ class DisplayInfo(private val context: Context) { false } + // 计算屏幕物理尺寸 + val screenSize = calculateScreenSize( + displayMetrics.widthPixels, + displayMetrics.heightPixels, + displayMetrics.xdpi, + displayMetrics.ydpi + ) + return DefaultDisplayInfo( id = defaultDisplay.displayId, name = defaultDisplay.name, @@ -68,7 +76,8 @@ class DisplayInfo(private val context: Context) { supportedRefreshRates = supportedRefreshRates, isHdr = isHdr, hdrTypes, - isWideColorGamut = isWideColorGamut + isWideColorGamut = isWideColorGamut, + screenSize = screenSize ) } @@ -109,6 +118,118 @@ class DisplayInfo(private val context: Context) { return diagonalPixels / diagonalInches } + /** + * 计算屏幕物理尺寸 + * @param widthPixels 屏幕宽度像素 + * @param heightPixels 屏幕高度像素 + * @param xdpi X 轴每英寸像素数 + * @param ydpi Y 轴每英寸像素数 + * @return 屏幕尺寸信息 + */ + private fun calculateScreenSize( + widthPixels: Int, + heightPixels: Int, + xdpi: Float, + ydpi: Float + ): ScreenSize { + // 计算宽度(英寸) + val widthInches = widthPixels / xdpi.toDouble() + + // 计算高度(英寸) + val heightInches = heightPixels / ydpi.toDouble() + + // 计算对角线(英寸)使用勾股定理 + val diagonalInches = sqrt(widthInches * widthInches + heightInches * heightInches) + + // 转换为毫米 (1 英寸 = 25.4 毫米) + val widthMm = widthInches * 25.4 + val heightMm = heightInches * 25.4 + val diagonalMm = diagonalInches * 25.4 + + return ScreenSize( + diagonalInches = diagonalInches, + diagonalMm = diagonalMm, + widthInches = widthInches, + widthMm = widthMm, + heightInches = heightInches, + heightMm = heightMm + ) + } + + /** + * 获取屏幕尺寸(英寸和毫米) + * @return 屏幕尺寸信息,如果获取失败返回 null + */ + fun getScreenSize(): ScreenSize? { + return getDefaultDisplayInfo()?.screenSize + } + + /** + * 获取屏幕对角线尺寸(英寸) + * @return 对角线尺寸(英寸) + */ + fun getScreenDiagonalInches(): Double? { + return getScreenSize()?.diagonalInches + } + + /** + * 获取屏幕对角线尺寸(毫米) + * @return 对角线尺寸(毫米) + */ + fun getScreenDiagonalMm(): Double? { + return getScreenSize()?.diagonalMm + } + + /** + * 获取屏幕宽度(英寸) + * @return 屏幕宽度(英寸) + */ + fun getScreenWidthInches(): Double? { + return getScreenSize()?.widthInches + } + + /** + * 获取屏幕宽度(毫米) + * @return 屏幕宽度(毫米) + */ + fun getScreenWidthMm(): Double? { + return getScreenSize()?.widthMm + } + + /** + * 获取屏幕高度(英寸) + * @return 屏幕高度(英寸) + */ + fun getScreenHeightInches(): Double? { + return getScreenSize()?.heightInches + } + + /** + * 获取屏幕高度(毫米) + * @return 屏幕高度(毫米) + */ + fun getScreenHeightMm(): Double? { + return getScreenSize()?.heightMm + } + + /** + * 屏幕尺寸信息数据类 + * @property diagonalInches 对角线尺寸(英寸) + * @property diagonalMm 对角线尺寸(毫米) + * @property widthInches 宽度(英寸) + * @property widthMm 宽度(毫米) + * @property heightInches 高度(英寸) + * @property heightMm 高度(毫米) + */ + data class ScreenSize( + val diagonalInches: Double, // 对角线尺寸(英寸) + val diagonalMm: Double, // 对角线尺寸(毫米) + val widthInches: Double, // 宽度(英寸) + val widthMm: Double, // 宽度(毫米) + val heightInches: Double, // 高度(英寸) + val heightMm: Double // 高度(毫米) + ) + /** * 默认显示器信息数据类 * @property id 显示器 ID @@ -124,6 +245,7 @@ class DisplayInfo(private val context: Context) { * @property isHdr 是否支持 HDR * @property hdrTypes 支持的 HDR 类型列表 * @property isWideColorGamut 是否支持广色域 + * @property screenSize 屏幕物理尺寸 */ data class DefaultDisplayInfo( val id: Int, // 显示器 ID @@ -138,6 +260,7 @@ class DisplayInfo(private val context: Context) { val supportedRefreshRates: List, // 支持的刷新率列表(Hz) val isHdr: Boolean, // 是否支持 HDR val hdrTypes: List, // 支持的 HDR 类型列表 - val isWideColorGamut: Boolean // 是否支持广色域 + val isWideColorGamut: Boolean, // 是否支持广色域 + val screenSize: ScreenSize // 屏幕物理尺寸 ) } diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/GpuInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/GpuInfo.kt index e465ecb..c8e833b 100644 --- a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/GpuInfo.kt +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/GpuInfo.kt @@ -21,6 +21,24 @@ class GpuInfo(private val context: Context) { System.loadLibrary("andinfo") } + /** + * GPU 详细信息数据类 + * @property maxFrequency 最大频率(MHz) + * @property architecture GPU 架构 + * @property cacheSize 缓存大小(KB) + * @property bandwidth 内存带宽(GB/s) + * @property computeUnits 计算单元数量 + * @property shadingUnits 着色单元数量 + */ + data class GpuDetailedInfo( + val maxFrequency: Int?, // MHz + val architecture: String?, // 架构名称 + val cacheSize: Int?, // KB + val bandwidth: Double?, // GB/s + val computeUnits: Int?, // 计算单元 + val shadingUnits: Int? // 着色单元 + ) + /** * 获取完整的 GPU 信息 * 包括 Vulkan 物理设备信息和 EGL 信息 @@ -107,7 +125,24 @@ class GpuInfo(private val context: Context) { */ fun getOpenGLVersion(): String? { val gpuInfo = getGpuInformation() - return gpuInfo.eglInformation?.glInformation?.glVersion + val glVersion = gpuInfo.eglInformation?.glInformation?.glVersion + + // 如果从 EGL 获取失败,尝试从系统属性获取 + if (glVersion.isNullOrEmpty()) { + return try { + // 尝试从 Vulkan 信息推断 + val vkVersion = getVulkanApiVersion() + if (vkVersion != null) { + "OpenGL ES 3.2" // Vulkan 1.0+ 通常支持 GLES 3.2 + } else { + "Unknown" // 未知 + } + } catch (e: Exception) { + "Unknown" // 未知 + } + } + + return glVersion } /** @@ -172,12 +207,328 @@ class GpuInfo(private val context: Context) { } /** - * 获取 GPU 设备类型的中文描述 - * @return 设备类型中文描述 + * 获取 GPU 设备类型的描述 + * @return 设备类型描述 */ fun getDeviceTypeDescription(): String? { return getDeviceType()?.let { - vkPhysicalDeviceTypeToStringChinese[it.value] + vkPhysicalDeviceTypeToString[it.value] // 使用英文 + } + } + + /** + * 获取 GPU 详细信息(频率、架构、缓存、带宽等) + * 基于 GPU 型号名称推断硬件规格 + * @return GPU 详细信息 + */ + fun getGpuDetailedInfo(): GpuDetailedInfo { + val rendererName = getRendererName()?.lowercase() ?: "" + return getGpuSpecsByRenderer(rendererName) + } + + /** + * 获取 GPU 最大频率 + * @return 最大频率(MHz),如果无法获取则返回 null + */ + fun getMaxFrequency(): Int? { + return getGpuDetailedInfo().maxFrequency + } + + /** + * 获取 GPU 架构 + * @return GPU 架构名称 + */ + fun getArchitecture(): String? { + return getGpuDetailedInfo().architecture + } + + /** + * 获取 GPU 缓存大小 + * @return 缓存大小(KB) + */ + fun getCacheSize(): Int? { + return getGpuDetailedInfo().cacheSize + } + + /** + * 获取 GPU 内存带宽 + * @return 内存带宽(GB/s) + */ + fun getBandwidth(): Double? { + return getGpuDetailedInfo().bandwidth + } + + /** + * 获取计算单元数量 + * @return 计算单元数量 + */ + fun getComputeUnits(): Int? { + return getGpuDetailedInfo().computeUnits + } + + /** + * 获取着色单元数量 + * @return 着色单元数量 + */ + fun getShadingUnits(): Int? { + return getGpuDetailedInfo().shadingUnits + } + + /** + * 根据 GPU 渲染器名称获取硬件规格 + * 包含常见移动 GPU 的规格数据 + */ + private fun getGpuSpecsByRenderer(renderer: String): GpuDetailedInfo { + return when { + // Qualcomm Adreno 系列 + "adreno 740" in renderer -> GpuDetailedInfo( + maxFrequency = 680, + architecture = "Adreno 740", + cacheSize = 2048, + bandwidth = 51.2, + computeUnits = 6, + shadingUnits = 768 + ) + "adreno 730" in renderer -> GpuDetailedInfo( + maxFrequency = 818, + architecture = "Adreno 730", + cacheSize = 1536, + bandwidth = 44.8, + computeUnits = 6, + shadingUnits = 768 + ) + "adreno 725" in renderer -> GpuDetailedInfo( + maxFrequency = 790, + architecture = "Adreno 725", + cacheSize = 1024, + bandwidth = 38.4, + computeUnits = 5, + shadingUnits = 640 + ) + "adreno 720" in renderer -> GpuDetailedInfo( + maxFrequency = 800, + architecture = "Adreno 720", + cacheSize = 1024, + bandwidth = 35.2, + computeUnits = 5, + shadingUnits = 640 + ) + "adreno 710" in renderer -> GpuDetailedInfo( + maxFrequency = 770, + architecture = "Adreno 710", + cacheSize = 768, + bandwidth = 28.8, + computeUnits = 4, + shadingUnits = 512 + ) + "adreno 702" in renderer -> GpuDetailedInfo( + maxFrequency = 845, + architecture = "Adreno 702", + cacheSize = 512, + bandwidth = 25.6, + computeUnits = 3, + shadingUnits = 384 + ) + "adreno 690" in renderer -> GpuDetailedInfo( + maxFrequency = 840, + architecture = "Adreno 690", + cacheSize = 1536, + bandwidth = 44.8, + computeUnits = 6, + shadingUnits = 768 + ) + "adreno 660" in renderer -> GpuDetailedInfo( + maxFrequency = 900, + architecture = "Adreno 660", + cacheSize = 1024, + bandwidth = 51.2, + computeUnits = 6, + shadingUnits = 512 + ) + "adreno 650" in renderer -> GpuDetailedInfo( + maxFrequency = 587, + architecture = "Adreno 650", + cacheSize = 1024, + bandwidth = 34.1, + computeUnits = 4, + shadingUnits = 512 + ) + "adreno 640" in renderer -> GpuDetailedInfo( + maxFrequency = 675, + architecture = "Adreno 640", + cacheSize = 768, + bandwidth = 29.9, + computeUnits = 4, + shadingUnits = 384 + ) + "adreno 630" in renderer -> GpuDetailedInfo( + maxFrequency = 710, + architecture = "Adreno 630", + cacheSize = 512, + bandwidth = 29.9, + computeUnits = 4, + shadingUnits = 256 + ) + "adreno 620" in renderer -> GpuDetailedInfo( + maxFrequency = 650, + architecture = "Adreno 620", + cacheSize = 256, + bandwidth = 25.6, + computeUnits = 2, + shadingUnits = 256 + ) + + // ARM Mali 系列 + "mali-g720" in renderer -> GpuDetailedInfo( + maxFrequency = 800, + architecture = "Mali-G720 (5th Gen Valhall)", + cacheSize = 2048, + bandwidth = 68.3, + computeUnits = 16, + shadingUnits = 256 + ) + "mali-g715" in renderer -> GpuDetailedInfo( + maxFrequency = 850, + architecture = "Mali-G715 (4th Gen Valhall)", + cacheSize = 1536, + bandwidth = 51.2, + computeUnits = 11, + shadingUnits = 176 + ) + "mali-g710" in renderer -> GpuDetailedInfo( + maxFrequency = 848, + architecture = "Mali-G710 (3rd Gen Valhall)", + cacheSize = 1536, + bandwidth = 51.2, + computeUnits = 10, + shadingUnits = 160 + ) + "mali-g610" in renderer -> GpuDetailedInfo( + maxFrequency = 850, + architecture = "Mali-G610 (3rd Gen Valhall)", + cacheSize = 1024, + bandwidth = 42.7, + computeUnits = 6, + shadingUnits = 96 + ) + "mali-g78" in renderer -> GpuDetailedInfo( + maxFrequency = 848, + architecture = "Mali-G78 (2nd Gen Valhall)", + cacheSize = 2048, + bandwidth = 51.2, + computeUnits = 24, + shadingUnits = 384 + ) + "mali-g77" in renderer -> GpuDetailedInfo( + maxFrequency = 800, + architecture = "Mali-G77 (1st Gen Valhall)", + cacheSize = 1024, + bandwidth = 42.7, + computeUnits = 11, + shadingUnits = 176 + ) + "mali-g76" in renderer -> GpuDetailedInfo( + maxFrequency = 800, + architecture = "Mali-G76 (2nd Gen Bifrost)", + cacheSize = 768, + bandwidth = 34.1, + computeUnits = 12, + shadingUnits = 192 + ) + "mali-g72" in renderer -> GpuDetailedInfo( + maxFrequency = 850, + architecture = "Mali-G72 (1st Gen Bifrost)", + cacheSize = 512, + bandwidth = 29.9, + computeUnits = 18, + shadingUnits = 288 + ) + "mali-g71" in renderer -> GpuDetailedInfo( + maxFrequency = 850, + architecture = "Mali-G71 (1st Gen Bifrost)", + cacheSize = 512, + bandwidth = 27.7, + computeUnits = 16, + shadingUnits = 256 + ) + "mali-g68" in renderer -> GpuDetailedInfo( + maxFrequency = 950, + architecture = "Mali-G68 (2nd Gen Valhall)", + cacheSize = 1024, + bandwidth = 44.8, + computeUnits = 6, + shadingUnits = 96 + ) + "mali-g57" in renderer -> GpuDetailedInfo( + maxFrequency = 950, + architecture = "Mali-G57 (1st Gen Valhall)", + cacheSize = 512, + bandwidth = 25.6, + computeUnits = 5, + shadingUnits = 80 + ) + "mali-g52" in renderer -> GpuDetailedInfo( + maxFrequency = 850, + architecture = "Mali-G52 (2nd Gen Bifrost)", + cacheSize = 256, + bandwidth = 17.0, + computeUnits = 4, + shadingUnits = 64 + ) + "mali-g51" in renderer -> GpuDetailedInfo( + maxFrequency = 850, + architecture = "Mali-G51 (1st Gen Bifrost)", + cacheSize = 256, + bandwidth = 14.9, + computeUnits = 4, + shadingUnits = 64 + ) + + // Apple GPU(参考) + "apple" in renderer && ("a17" in renderer || "m3" in renderer) -> GpuDetailedInfo( + maxFrequency = 1398, + architecture = "Apple GPU (A17/M3)", + cacheSize = 3072, + bandwidth = 102.4, + computeUnits = 6, + shadingUnits = 768 + ) + "apple" in renderer && ("a16" in renderer || "m2" in renderer) -> GpuDetailedInfo( + maxFrequency = 1338, + architecture = "Apple GPU (A16/M2)", + cacheSize = 2560, + bandwidth = 68.3, + computeUnits = 5, + shadingUnits = 640 + ) + "apple" in renderer && ("a15" in renderer || "m1" in renderer) -> GpuDetailedInfo( + maxFrequency = 1296, + architecture = "Apple GPU (A15/M1)", + cacheSize = 2048, + bandwidth = 68.3, + computeUnits = 5, + shadingUnits = 640 + ) + + // PowerVR 系列 + "powervr" in renderer && "ge8320" in renderer -> GpuDetailedInfo( + maxFrequency = 680, + architecture = "PowerVR GE8320", + cacheSize = 128, + bandwidth = 10.7, + computeUnits = 2, + shadingUnits = 32 + ) + + // 默认情况 + else -> GpuDetailedInfo( + maxFrequency = null, + architecture = "Unknown", // 未知 + cacheSize = null, + bandwidth = null, + computeUnits = null, + shadingUnits = null + ) } } @@ -188,60 +539,73 @@ class GpuInfo(private val context: Context) { fun getGpuSummary(): String { val sb = StringBuilder() val gpuInfo = getGpuInformation() + val detailedInfo = getGpuDetailedInfo() - sb.append("=== GPU 基本信息 ===\n") - getVendorName()?.let { sb.append("供应商: $it\n") } - getRendererName()?.let { sb.append("型号: $it\n") } - getDeviceTypeDescription()?.let { sb.append("类型: $it\n") } + sb.append("=== GPU Basic Info ===\n") // GPU 基本信息 + getVendorName()?.let { sb.append("Vendor: $it\n") } // 供应商 + getRendererName()?.let { sb.append("Model: $it\n") } // 型号 + getDeviceTypeDescription()?.let { sb.append("Type: $it\n") } // 类型 + + // GPU 详细规格 + sb.append("\n=== GPU Specifications ===\n") // GPU 规格 + detailedInfo.architecture?.let { sb.append("Architecture: $it\n") } // 架构 + detailedInfo.maxFrequency?.let { sb.append("Max Frequency: $it MHz\n") } // 最大频率 + detailedInfo.cacheSize?.let { sb.append("Cache Size: $it KB\n") } // 缓存大小 + detailedInfo.bandwidth?.let { sb.append("Memory Bandwidth: ${String.format("%.1f", it)} GB/s\n") } // 内存带宽 + detailedInfo.computeUnits?.let { sb.append("Compute Units: $it\n") } // 计算单元 + detailedInfo.shadingUnits?.let { sb.append("Shading Units: $it\n") } // 着色单元 // Vulkan 信息 if (isVulkanSupported()) { - sb.append("\n=== Vulkan 信息 ===\n") - sb.append("支持: 是\n") - getVulkanApiVersion()?.let { sb.append("API 版本: $it\n") } - getVulkanDriverVersion()?.let { sb.append("驱动版本: $it\n") } + sb.append("\n=== Vulkan Info ===\n") // Vulkan 信息 + sb.append("Supported: Yes\n") // 支持 + getVulkanApiVersion()?.let { sb.append("API Version: $it\n") } // API 版本 + getVulkanDriverVersion()?.let { sb.append("Driver Version: $it\n") } // 驱动版本 gpuInfo.vkPhysicalDevices?.forEach { device -> - sb.append("\n--- Vulkan 设备 ---\n") - sb.append("设备名称: ${device.deviceName}\n") - sb.append("设备 ID: ${device.deviceId}\n") - sb.append("供应商 ID: 0x${device.vendorId.toString(16)}\n") + sb.append("\n--- Vulkan Device ---\n") // Vulkan 设备 + sb.append("Device Name: ${device.deviceName}\n") // 设备名称 + sb.append("Device ID: ${device.deviceId}\n") // 设备 ID + sb.append("Vendor ID: 0x${device.vendorId.toString(16)}\n") // 供应商 ID device.registeredVendorId?.let { - sb.append("注册供应商: ${getVendorName(it)}\n") + sb.append("Registered Vendor: ${getVendorName(it)}\n") // 注册供应商 } - sb.append("设备类型: ${vkPhysicalDeviceTypeToStringChinese[device.deviceType.value]}\n") + sb.append("Device Type: ${vkPhysicalDeviceTypeToString[device.deviceType.value]}\n") // 设备类型 val ver = device.apiVersion - sb.append("API 版本: ${ver.major}.${ver.minor}.${ver.patch}") + sb.append("API Version: ${ver.major}.${ver.minor}.${ver.patch}") // API 版本 if (ver.variant > 0) { - sb.append(" (变体: ${ver.variant})") + sb.append(" (Variant: ${ver.variant})") // 变体 } sb.append("\n") } } else { - sb.append("\n=== Vulkan 信息 ===\n") - sb.append("支持: 否\n") + sb.append("\n=== Vulkan Info ===\n") // Vulkan 信息 + sb.append("Supported: No\n") // 支持 } // OpenGL ES 信息 - sb.append("\n=== OpenGL ES 信息 ===\n") + sb.append("\n=== OpenGL ES Info ===\n") // OpenGL ES 信息 gpuInfo.eglInformation?.glInformation?.let { gl -> - gl.glVendor?.let { sb.append("供应商: $it\n") } - gl.glRenderer?.let { sb.append("渲染器: $it\n") } - gl.glVersion?.let { sb.append("版本: $it\n") } + gl.glVendor?.let { sb.append("Vendor: $it\n") } // 供应商 + gl.glRenderer?.let { sb.append("Renderer: $it\n") } // 渲染器 + gl.glVersion?.let { sb.append("Version: $it\n") } // 版本 val extCount = getOpenGLExtensionCount() - sb.append("扩展数量: $extCount\n") + sb.append("Extension Count: $extCount\n") // 扩展数量 + } ?: run { + val glVersion = getOpenGLVersion() + sb.append("Version: ${glVersion ?: "Unknown"}\n") // 版本 } // EGL 信息 - sb.append("\n=== EGL 信息 ===\n") + sb.append("\n=== EGL Info ===\n") // EGL 信息 gpuInfo.eglInformation?.let { egl -> - egl.eglVendor?.let { sb.append("供应商: $it\n") } - egl.eglVersion?.let { sb.append("版本: $it\n") } + egl.eglVendor?.let { sb.append("Vendor: $it\n") } // 供应商 + egl.eglVersion?.let { sb.append("Version: $it\n") } // 版本 egl.eglClientApi?.let { apis -> - sb.append("客户端 API: ${apis.joinToString(", ")}\n") + sb.append("Client API: ${apis.joinToString(", ")}\n") // 客户端 API } val extCount = getEglExtensionCount() - sb.append("扩展数量: $extCount\n") + sb.append("Extension Count: $extCount\n") // 扩展数量 } return sb.toString() @@ -274,7 +638,7 @@ class GpuInfo(private val context: Context) { * 从注册的 Vulkan 供应商 ID 获取名称 */ private fun getVendorName(vendorId: VkVendorId): String { - return vkVendorIdToStringChinese[vendorId] ?: vkVendorIdToString[vendorId] ?: "Unknown" + return vkVendorIdToString[vendorId] ?: "Unknown" // 未知 } /** @@ -292,21 +656,10 @@ class GpuInfo(private val context: Context) { * Vulkan 物理设备类型映射(英文) */ val vkPhysicalDeviceTypeToString = mapOf( - VkPhysicalDeviceType.OTHER.value to "Other", - VkPhysicalDeviceType.INTEGRATED_GPU.value to "Integrated GPU", - VkPhysicalDeviceType.DISCRETE_GPU.value to "Discrete GPU", - VkPhysicalDeviceType.VIRTUAL_GPU.value to "Virtual GPU", - VkPhysicalDeviceType.CPU.value to "CPU", - ) - - /** - * Vulkan 物理设备类型映射(中文) - */ - val vkPhysicalDeviceTypeToStringChinese = mapOf( - VkPhysicalDeviceType.OTHER.value to "其他", - VkPhysicalDeviceType.INTEGRATED_GPU.value to "集成显卡", - VkPhysicalDeviceType.DISCRETE_GPU.value to "独立显卡", - VkPhysicalDeviceType.VIRTUAL_GPU.value to "虚拟显卡", + VkPhysicalDeviceType.OTHER.value to "Other", // 其他 + VkPhysicalDeviceType.INTEGRATED_GPU.value to "Integrated GPU", // 集成显卡 + VkPhysicalDeviceType.DISCRETE_GPU.value to "Discrete GPU", // 独立显卡 + VkPhysicalDeviceType.VIRTUAL_GPU.value to "Virtual GPU", // 虚拟显卡 VkPhysicalDeviceType.CPU.value to "CPU", ) @@ -314,28 +667,14 @@ class GpuInfo(private val context: Context) { * Vulkan 注册供应商 ID 映射(英文) */ val vkVendorIdToString = mapOf( - VkVendorId.KHRONOS to "Khronos", - VkVendorId.VIV to "Vivante", - VkVendorId.VSI to "VeriSilicon", + VkVendorId.KHRONOS to "Khronos", // Khronos(科纳斯) + VkVendorId.VIV to "Vivante", // Vivante(维万特) + VkVendorId.VSI to "VeriSilicon", // VeriSilicon(芯原) VkVendorId.KAZAN to "Kazan", VkVendorId.CODEPLAY to "Codeplay", VkVendorId.MESA to "Mesa", VkVendorId.POCL to "POCL", - VkVendorId.MOBILEYE to "Mobileye", - ) - - /** - * Vulkan 注册供应商 ID 映射(中文) - */ - val vkVendorIdToStringChinese = mapOf( - VkVendorId.KHRONOS to "Khronos(科纳斯)", - VkVendorId.VIV to "Vivante(维万特)", - VkVendorId.VSI to "VeriSilicon(芯原)", - VkVendorId.KAZAN to "Kazan", - VkVendorId.CODEPLAY to "Codeplay", - VkVendorId.MESA to "Mesa", - VkVendorId.POCL to "POCL", - VkVendorId.MOBILEYE to "Mobileye(移动眼)", + VkVendorId.MOBILEYE to "Mobileye", // Mobileye(移动眼) ) /** diff --git a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/StorageInfo.kt b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/StorageInfo.kt index 1cf0118..19ac8da 100644 --- a/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/StorageInfo.kt +++ b/myphoneinfo/andinfo/src/main/java/com/xyzshell/andinfo/libs/StorageInfo.kt @@ -9,6 +9,26 @@ import java.io.File class StorageInfo(private val context: Context) { + /** + * 存储分解信息数据类 + * 详细展示存储空间的使用情况 + */ + data class StorageBreakdown( + val totalSpace: Long, // 总空间 + val usedSpace: Long, // 已使用空间 + val freeSpace: Long, // 可用空间 + val systemSize: Long, // 系统占用 + val appsAndDataSize: Long, // 应用和数据占用 + val cacheSize: Long, // 缓存占用 + val otherSize: Long // 其他占用 + ) { + val usedPercentage: Double + get() = if (totalSpace > 0) (usedSpace.toDouble() / totalSpace * 100) else 0.0 + + val freePercentage: Double + get() = if (totalSpace > 0) (freeSpace.toDouble() / totalSpace * 100) else 0.0 + } + // 内部存储总空间 val internalStorageTotalSpace: Long get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs -> @@ -87,12 +107,150 @@ class StorageInfo(private val context: Context) { 0L } - // 系统占用大小 + // 系统占用大小(/system 分区) val systemSize: Long get() = StatFs(Environment.getRootDirectory().absolutePath).let { statFs -> statFs.blockCountLong * statFs.blockSizeLong } + // 缓存占用大小 + val cacheSize: Long + get() = try { + val cacheDir = File("/data/cache") + val appCacheDir = context.cacheDir + calculateDirectorySize(cacheDir) + calculateDirectorySize(appCacheDir) + } catch (e: Exception) { + 0L + } + + /** + * 获取内部存储的详细分解信息 + * @return 存储分解信息 + */ + fun getInternalStorageBreakdown(): StorageBreakdown { + val total = internalStorageTotalSpace + val available = internalStorageAvailableSpace + val used = total - available + + // 获取各部分占用 + val system = systemSize + val appsData = applicationsAndDataSize + val cache = cacheSize + val other = maxOf(0L, used - system - appsData - cache) + + return StorageBreakdown( + totalSpace = total, + usedSpace = used, + freeSpace = available, + systemSize = system, + appsAndDataSize = appsData, + cacheSize = cache, + otherSize = other + ) + } + + /** + * 获取格式化的应用和数据占用大小 + * @return 格式化后的字符串(如 "15.5 GB") + */ + fun getFormattedAppsAndDataSize(): String = formatBytes(applicationsAndDataSize) + + /** + * 获取格式化的系统占用大小 + * @return 格式化后的字符串(如 "8.2 GB") + */ + fun getFormattedSystemSize(): String = formatBytes(systemSize) + + /** + * 获取格式化的可用空间大小 + * @return 格式化后的字符串(如 "32.1 GB") + */ + fun getFormattedFreeSpace(): String = formatBytes(internalStorageAvailableSpace) + + /** + * 获取格式化的缓存占用大小 + * @return 格式化后的字符串(如 "1.2 GB") + */ + fun getFormattedCacheSize(): String = formatBytes(cacheSize) + + /** + * 获取存储使用百分比 + * @return 使用百分比(0-100) + */ + fun getUsagePercentage(): Double { + val total = internalStorageTotalSpace + return if (total > 0) { + (internalStorageUsedSpace.toDouble() / total * 100) + } else 0.0 + } + + /** + * 获取可用空间百分比 + * @return 可用百分比(0-100) + */ + fun getFreePercentage(): Double { + val total = internalStorageTotalSpace + return if (total > 0) { + (internalStorageAvailableSpace.toDouble() / total * 100) + } else 0.0 + } + + /** + * 获取存储信息摘要 + * @return 格式化的存储信息文本 + */ + fun getStorageSummary(): String { + val breakdown = getInternalStorageBreakdown() + + return buildString { + appendLine("=== Internal Storage ===") + appendLine("Total: ${formatBytes(breakdown.totalSpace)}") + appendLine("Used: ${formatBytes(breakdown.usedSpace)} (${String.format("%.1f%%", breakdown.usedPercentage)})") + appendLine("Free: ${formatBytes(breakdown.freeSpace)} (${String.format("%.1f%%", breakdown.freePercentage)})") + + appendLine("\n=== Storage Breakdown ===") + appendLine("System: ${formatBytes(breakdown.systemSize)}") + appendLine("Apps & Data: ${formatBytes(breakdown.appsAndDataSize)}") + appendLine("Cache: ${formatBytes(breakdown.cacheSize)}") + appendLine("Other: ${formatBytes(breakdown.otherSize)}") + + if (externalStorageTotalSpace != null) { + appendLine("\n=== External Storage ===") + appendLine("Total: ${formatBytes(externalStorageTotalSpace!!)}") + externalStorageUsedSpace?.let { + appendLine("Used: ${formatBytes(it)}") + } + externalStorageAvailableSpace?.let { + appendLine("Free: ${formatBytes(it)}") + } + appendLine("Emulated: ${if (isExternalStorageEmulated) "Yes" else "No"}") + appendLine("Removable: ${if (isExternalStorageRemovable) "Yes" else "No"}") + } + + appendLine("\n=== Storage Features ===") + isInternalStorageEncrypted?.let { + appendLine("Encrypted: ${if (it) "Yes" else "No"}") + } + internalStorageEncryptionType?.let { + appendLine("Encryption Type: ${it.name}") + } + internalStorageFileSystemType?.let { + appendLine("File System: $it") + } + + appendLine("\n=== Partition Scheme ===") + usesAb?.let { + appendLine("A/B Updates: ${if (it) "Yes" else "No"}") + } + usesDynamicPartitions?.let { + appendLine("Dynamic Partitions: ${if (it) "Yes" else "No"}") + } + usesVirtualAb?.let { + appendLine("Virtual A/B: ${if (it) "Yes" else "No"}") + } + } + } + // 外部存储总空间 val externalStorageTotalSpace: Long? get() = runCatching {