Compare commits

...

2 Commits

Author SHA1 Message Date
xsean
264a45f4db Merge branch 'main' of http://git.zhenbs.com:9999/2-group-android/DevCheck-lib 2025-12-29 11:39:23 +08:00
xsean
6374b15a31 修改 2025-12-29 11:39:18 +08:00
10 changed files with 3055 additions and 220 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"FSharp.suggestGitignore": false
}

View File

@ -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<Long>, // 可用频率列表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
- 向后兼容: 所有原有方法保持不变

View File

@ -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 布局自适应
- 字体大小调整
- 图片资源选择
- 视频播放优化
- 游戏控制布局
- 阅读体验优化
- 设备分类统计
- 用户体验研究

View File

@ -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
- **入门级**: 其他

671
StorageInfo使用示例.md Normal file
View File

@ -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. **用户提醒**: 低存储空间警告

View File

@ -163,10 +163,10 @@ class CameraInfo(private val context: Context) {
*/ */
fun getCameraFacingText(characteristics: CameraCharacteristics): String { fun getCameraFacingText(characteristics: CameraCharacteristics): String {
return when (getCameraFacing(characteristics)) { return when (getCameraFacing(characteristics)) {
CameraFacing.BACK -> "后置" CameraFacing.BACK -> "Back" // 后置
CameraFacing.FRONT -> "前置" CameraFacing.FRONT -> "Front" // 前置
CameraFacing.EXTERNAL -> "外置" CameraFacing.EXTERNAL -> "External" // 外置
else -> "未知" 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_GBRG -> "GBRG (Bayer)"
CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR -> "BGGR (Bayer)" CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR -> "BGGR (Bayer)"
CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB -> "RGB" CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB -> "RGB"
5 -> "Mono/NIR (单色/近红外)" // MONO/NIR 5 -> "Mono/NIR" // 单色/近红外
else -> "未知" else -> "Unknown" // 未知
} }
} }
} }
@ -409,8 +409,8 @@ class CameraInfo(private val context: Context) {
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL -> "FULL" CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL -> "FULL"
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY -> "LEGACY" CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY -> "LEGACY"
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 -> "LEVEL_3" 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 "未知" CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "EXTERNAL" else "Unknown" // 未知
else -> "未知" else -> "Unknown" // 未知
} }
} }
} }
@ -430,10 +430,10 @@ class CameraInfo(private val context: Context) {
fun getFaceDetectionModes(characteristics: CameraCharacteristics): List<String>? { fun getFaceDetectionModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES)?.map { return characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES)?.map {
when (it) { when (it) {
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_OFF -> "关闭" CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_OFF -> "Off" // 关闭
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE -> "简单" CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE -> "Simple" // 简单
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_FULL -> "完整" CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_FULL -> "Full" // 完整
else -> "未知" else -> "Unknown" // 未知
} }
} }
} }
@ -480,17 +480,17 @@ class CameraInfo(private val context: Context) {
val features = mutableListOf<String>() val features = mutableListOf<String>()
val capabilities = getAvailableCapabilities(characteristics) val capabilities = getAvailableCapabilities(characteristics)
if (capabilities.contains(CameraCapability.RAW)) features.add("RAW拍摄") if (capabilities.contains(CameraCapability.RAW)) features.add("RAW Capture") // RAW拍摄
if (capabilities.contains(CameraCapability.BURST_CAPTURE)) features.add("连拍") if (capabilities.contains(CameraCapability.BURST_CAPTURE)) features.add("Burst Capture") // 连拍
if (capabilities.contains(CameraCapability.DEPTH_OUTPUT)) features.add("景深输出") if (capabilities.contains(CameraCapability.DEPTH_OUTPUT)) features.add("Depth Output") // 景深输出
if (capabilities.contains(CameraCapability.CONSTRAINED_HIGH_SPEED_VIDEO)) features.add("高速视频") if (capabilities.contains(CameraCapability.CONSTRAINED_HIGH_SPEED_VIDEO)) features.add("High Speed Video") // 高速视频
if (capabilities.contains(CameraCapability.MANUAL_SENSOR)) features.add("手动模式") if (capabilities.contains(CameraCapability.MANUAL_SENSOR)) features.add("Manual Mode") // 手动模式
if (capabilities.contains(CameraCapability.MONOCHROME)) features.add("黑白模式") if (capabilities.contains(CameraCapability.MONOCHROME)) features.add("Monochrome Mode") // 黑白模式
if (capabilities.contains(CameraCapability.ULTRA_HIGH_RESOLUTION_SENSOR)) features.add("超高分辨率") 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 (capabilities.contains(CameraCapability.DYNAMIC_RANGE_TEN_BIT)) features.add("10-bit HDR")
if (hasOpticalStabilization(characteristics)) features.add("光学防抖") if (hasOpticalStabilization(characteristics)) features.add("Optical Stabilization") // 光学防抖
if (hasVideoStabilization(characteristics)) features.add("视频防抖") if (hasVideoStabilization(characteristics)) features.add("Video Stabilization") // 视频防抖
return features return features
} }
@ -503,13 +503,13 @@ class CameraInfo(private val context: Context) {
fun getAutoExposureModes(characteristics: CameraCharacteristics): List<String>? { fun getAutoExposureModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES)?.map { return characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES)?.map {
when (it) { when (it) {
CameraCharacteristics.CONTROL_AE_MODE_OFF -> "关闭" CameraCharacteristics.CONTROL_AE_MODE_OFF -> "Off" // 关闭
CameraCharacteristics.CONTROL_AE_MODE_ON -> "自动" CameraCharacteristics.CONTROL_AE_MODE_ON -> "Auto" // 自动
CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH -> "自动闪光" CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH -> "Auto Flash" // 自动闪光
CameraCharacteristics.CONTROL_AE_MODE_ON_ALWAYS_FLASH -> "强制闪光" CameraCharacteristics.CONTROL_AE_MODE_ON_ALWAYS_FLASH -> "Always Flash" // 强制闪光
CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE -> "防红眼" 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) "外置闪光" else "未知" CameraCharacteristics.CONTROL_AE_MODE_ON_EXTERNAL_FLASH -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "External Flash" else "Unknown" // 外置闪光/未知
else -> "未知" else -> "Unknown" // 未知
} }
} }
} }
@ -520,13 +520,13 @@ class CameraInfo(private val context: Context) {
fun getAutoFocusModes(characteristics: CameraCharacteristics): List<String>? { fun getAutoFocusModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES)?.map { return characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES)?.map {
when (it) { when (it) {
CameraCharacteristics.CONTROL_AF_MODE_OFF -> "关闭" CameraCharacteristics.CONTROL_AF_MODE_OFF -> "Off" // 关闭
CameraCharacteristics.CONTROL_AF_MODE_AUTO -> "自动" CameraCharacteristics.CONTROL_AF_MODE_AUTO -> "Auto" // 自动
CameraCharacteristics.CONTROL_AF_MODE_MACRO -> "微距" CameraCharacteristics.CONTROL_AF_MODE_MACRO -> "Macro" // 微距
CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_VIDEO -> "连续视频" CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_VIDEO -> "Continuous Video" // 连续视频
CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_PICTURE -> "连续拍照" CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_PICTURE -> "Continuous Picture" // 连续拍照
CameraCharacteristics.CONTROL_AF_MODE_EDOF -> "EDOF" CameraCharacteristics.CONTROL_AF_MODE_EDOF -> "EDOF"
else -> "未知" else -> "Unknown" // 未知
} }
} }
} }
@ -537,16 +537,16 @@ class CameraInfo(private val context: Context) {
fun getWhiteBalanceModes(characteristics: CameraCharacteristics): List<String>? { fun getWhiteBalanceModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES)?.map { return characteristics.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES)?.map {
when (it) { when (it) {
CameraCharacteristics.CONTROL_AWB_MODE_OFF -> "关闭" CameraCharacteristics.CONTROL_AWB_MODE_OFF -> "Off" // 关闭
CameraCharacteristics.CONTROL_AWB_MODE_AUTO -> "自动" CameraCharacteristics.CONTROL_AWB_MODE_AUTO -> "Auto" // 自动
CameraCharacteristics.CONTROL_AWB_MODE_INCANDESCENT -> "白炽灯" CameraCharacteristics.CONTROL_AWB_MODE_INCANDESCENT -> "Incandescent" // 白炽灯
CameraCharacteristics.CONTROL_AWB_MODE_FLUORESCENT -> "荧光灯" CameraCharacteristics.CONTROL_AWB_MODE_FLUORESCENT -> "Fluorescent" // 荧光灯
CameraCharacteristics.CONTROL_AWB_MODE_WARM_FLUORESCENT -> "暖荧光" CameraCharacteristics.CONTROL_AWB_MODE_WARM_FLUORESCENT -> "Warm Fluorescent" // 暖荧光
CameraCharacteristics.CONTROL_AWB_MODE_DAYLIGHT -> "日光" CameraCharacteristics.CONTROL_AWB_MODE_DAYLIGHT -> "Daylight" // 日光
CameraCharacteristics.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT -> "阴天" CameraCharacteristics.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT -> "Cloudy" // 阴天
CameraCharacteristics.CONTROL_AWB_MODE_TWILIGHT -> "黄昏" CameraCharacteristics.CONTROL_AWB_MODE_TWILIGHT -> "Twilight" // 黄昏
CameraCharacteristics.CONTROL_AWB_MODE_SHADE -> "阴影" CameraCharacteristics.CONTROL_AWB_MODE_SHADE -> "Shade" // 阴影
else -> "未知" else -> "Unknown" // 未知
} }
} }
} }
@ -557,26 +557,26 @@ class CameraInfo(private val context: Context) {
fun getSceneModes(characteristics: CameraCharacteristics): List<String>? { fun getSceneModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES)?.map { return characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES)?.map {
when (it) { when (it) {
CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED -> "禁用" CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED -> "Disabled" // 禁用
CameraCharacteristics.CONTROL_SCENE_MODE_FACE_PRIORITY -> "人像优先" CameraCharacteristics.CONTROL_SCENE_MODE_FACE_PRIORITY -> "Face Priority" // 人像优先
CameraCharacteristics.CONTROL_SCENE_MODE_ACTION -> "运动" CameraCharacteristics.CONTROL_SCENE_MODE_ACTION -> "Action" // 运动
CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT -> "人像" CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT -> "Portrait" // 人像
CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE -> "风景" CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE -> "Landscape" // 风景
CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT -> "夜景" CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT -> "Night" // 夜景
CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT -> "夜景人像" CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT -> "Night Portrait" // 夜景人像
CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE -> "剧院" CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE -> "Theatre" // 剧院
CameraCharacteristics.CONTROL_SCENE_MODE_BEACH -> "海滩" CameraCharacteristics.CONTROL_SCENE_MODE_BEACH -> "Beach" // 海滩
CameraCharacteristics.CONTROL_SCENE_MODE_SNOW -> "雪景" CameraCharacteristics.CONTROL_SCENE_MODE_SNOW -> "Snow" // 雪景
CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET -> "日落" CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET -> "Sunset" // 日落
CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO -> "防抖" CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO -> "Steady Photo" // 防抖
CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS -> "烟火" CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS -> "Fireworks" // 烟火
CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS -> "体育" CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS -> "Sports" // 体育
CameraCharacteristics.CONTROL_SCENE_MODE_PARTY -> "派对" CameraCharacteristics.CONTROL_SCENE_MODE_PARTY -> "Party" // 派对
CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT -> "烛光" CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT -> "Candlelight" // 烛光
CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE -> "条形码" CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE -> "Barcode" // 条形码
CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) "高速视频" else "未知" 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" CameraCharacteristics.CONTROL_SCENE_MODE_HDR -> "HDR"
else -> "未知" else -> "Unknown" // 未知
} }
} }
} }
@ -587,16 +587,16 @@ class CameraInfo(private val context: Context) {
fun getColorEffects(characteristics: CameraCharacteristics): List<String>? { fun getColorEffects(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS)?.map { return characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS)?.map {
when (it) { when (it) {
CameraCharacteristics.CONTROL_EFFECT_MODE_OFF -> "关闭" CameraCharacteristics.CONTROL_EFFECT_MODE_OFF -> "Off" // 关闭
CameraCharacteristics.CONTROL_EFFECT_MODE_MONO -> "黑白" CameraCharacteristics.CONTROL_EFFECT_MODE_MONO -> "Mono" // 黑白
CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE -> "负片" CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE -> "Negative" // 负片
CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE -> "曝光" CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE -> "Solarize" // 曝光
CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA -> "棕褐色" CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA -> "Sepia" // 棕褐色
CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE -> "海报化" CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE -> "Posterize" // 海报化
CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD -> "白板" CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD -> "Whiteboard" // 白板
CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD -> "黑板" CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD -> "Blackboard" // 黑板
CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA -> "水蓝" CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA -> "Aqua" // 水蓝
else -> "未知" else -> "Unknown" // 未知
} }
} }
} }

View File

@ -32,6 +32,63 @@ class CpuInfo {
val cores: List<Core> val cores: List<Core>
get() = CpuInfoUtils.getCores() 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<Long>,
val speedMetric: Double
)
/**
* 获取所有核心的详细信息包含频率和速度度量
* @return 详细核心信息列表
*/
fun getCoresDetailedInfo(): List<CoreDetailedInfo> {
val coresList = cores
val result = mutableListOf<CoreDetailedInfo>()
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 集群列表 * @return 集群列表
@ -100,7 +157,7 @@ class CpuInfo {
return if (packages.isNotEmpty()) { return if (packages.isNotEmpty()) {
packages[0].name packages[0].name
} else { } else {
"未知" "Unknown" // 未知
} }
} }
@ -112,7 +169,7 @@ class CpuInfo {
return if (cores.isNotEmpty()) { return if (cores.isNotEmpty()) {
cores[0].vendor.name cores[0].vendor.name
} else { } else {
"未知" "Unknown" // 未知
} }
} }
@ -205,7 +262,7 @@ class CpuInfo {
/** /**
* 制程信息数据类 * 制程信息数据类
* @property process 制程工艺例如 "4nm", "5nm", "7nm" * @property process 制程工艺例如 "4nm", "5nm", "7nm"
* @property foundry 代工厂例如 "台积电", "三星" * @property foundry 代工厂例如 "TSMC", "Samsung"
* @property node 详细制程节点例如 "TSMC N4P", "Samsung 4LPE" * @property node 详细制程节点例如 "TSMC N4P", "Samsung 4LPE"
*/ */
data class ProcessInfo( data class ProcessInfo(
@ -224,110 +281,110 @@ class CpuInfo {
return when { return when {
// 高通 Snapdragon 8 系列 // 高通 Snapdragon 8 系列
"snapdragon 8 gen 3" in processorName || "sm8650" in processorName -> "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 -> "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 -> "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 -> "snapdragon 888+" in processorName || "sm8350-ab" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
"snapdragon 888" in processorName || "sm8350" in processorName -> "snapdragon 888" in processorName || "sm8350" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
"snapdragon 870" in processorName || "sm8250-ac" in processorName -> "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 -> "snapdragon 865+" in processorName || "sm8250-ab" in processorName ->
ProcessInfo("7nm", "台积电", "TSMC N7P") ProcessInfo("7nm", "TSMC", "TSMC N7P") // 台积电
"snapdragon 865" in processorName || "sm8250" in processorName -> "snapdragon 865" in processorName || "sm8250" in processorName ->
ProcessInfo("7nm", "台积电", "TSMC N7P") ProcessInfo("7nm", "TSMC", "TSMC N7P") // 台积电
// 高通 Snapdragon 7 系列 // 高通 Snapdragon 7 系列
"snapdragon 7+ gen 2" in processorName || "sm7475" in processorName -> "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 -> "snapdragon 778g" in processorName || "sm7325" in processorName ->
ProcessInfo("6nm", "台积电", "TSMC N6") ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
// 高通 Snapdragon 6 系列 // 高通 Snapdragon 6 系列
"snapdragon 695" in processorName || "sm6375" in processorName -> "snapdragon 695" in processorName || "sm6375" in processorName ->
ProcessInfo("6nm", "台积电", "TSMC N6") ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
// 联发科 Dimensity 9000 系列 // 联发科 Dimensity 9000 系列
"dimensity 9300" in processorName || "mt6989" in processorName -> "dimensity 9300" in processorName || "mt6989" in processorName ->
ProcessInfo("4nm", "台积电", "TSMC N4P") ProcessInfo("4nm", "TSMC", "TSMC N4P") // 台积电
"dimensity 9200+" in processorName || "mt6985" in processorName -> "dimensity 9200+" in processorName || "mt6985" in processorName ->
ProcessInfo("4nm", "台积电", "TSMC N4") ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
"dimensity 9200" in processorName || "mt6983" in processorName -> "dimensity 9200" in processorName || "mt6983" in processorName ->
ProcessInfo("4nm", "台积电", "TSMC N4") ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
"dimensity 9000+" in processorName || "mt6985" in processorName -> "dimensity 9000+" in processorName || "mt6985" in processorName ->
ProcessInfo("4nm", "台积电", "TSMC N4") ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
"dimensity 9000" in processorName || "mt6983" in processorName -> "dimensity 9000" in processorName || "mt6983" in processorName ->
ProcessInfo("4nm", "台积电", "TSMC N4") ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
// 联发科 Dimensity 8000 系列 // 联发科 Dimensity 8000 系列
"dimensity 8300" in processorName || "mt6897" in processorName -> "dimensity 8300" in processorName || "mt6897" in processorName ->
ProcessInfo("4nm", "台积电", "TSMC N4") ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
"dimensity 8200" in processorName || "mt6896" in processorName -> "dimensity 8200" in processorName || "mt6896" in processorName ->
ProcessInfo("4nm", "台积电", "TSMC N4") ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
"dimensity 8100" in processorName || "mt6895" in processorName -> "dimensity 8100" in processorName || "mt6895" in processorName ->
ProcessInfo("5nm", "台积电", "TSMC N5") ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电
// 联发科 Dimensity 1000 系列 // 联发科 Dimensity 1000 系列
"dimensity 1200" in processorName || "mt6893" in processorName -> "dimensity 1200" in processorName || "mt6893" in processorName ->
ProcessInfo("6nm", "台积电", "TSMC N6") ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
"dimensity 1080" in processorName || "mt6877" in processorName -> "dimensity 1080" in processorName || "mt6877" in processorName ->
ProcessInfo("6nm", "台积电", "TSMC N6") ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
// 联发科 Helio 系列 // 联发科 Helio 系列
"helio g99" in processorName || "mt6789" in processorName -> "helio g99" in processorName || "mt6789" in processorName ->
ProcessInfo("6nm", "台积电", "TSMC N6") ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
// 三星 Exynos // 三星 Exynos
"exynos 2400" in processorName || "s5e9945" in processorName -> "exynos 2400" in processorName || "s5e9945" in processorName ->
ProcessInfo("4nm", "三星", "Samsung 4LPP+") ProcessInfo("4nm", "Samsung", "Samsung 4LPP+") // 三星
"exynos 2200" in processorName || "s5e9925" in processorName -> "exynos 2200" in processorName || "s5e9925" in processorName ->
ProcessInfo("4nm", "三星", "Samsung 4LPE") ProcessInfo("4nm", "Samsung", "Samsung 4LPE") // 三星
"exynos 2100" in processorName || "s5e9840" in processorName -> "exynos 2100" in processorName || "s5e9840" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
"exynos 1080" in processorName || "s5e1080" in processorName -> "exynos 1080" in processorName || "s5e1080" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
"exynos 1380" in processorName || "s5e8835" in processorName -> "exynos 1380" in processorName || "s5e8835" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
"exynos 1280" in processorName || "s5e8825" in processorName -> "exynos 1280" in processorName || "s5e8825" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
// 谷歌 Tensor // 谷歌 Tensor
"tensor g3" in processorName || "gs301" in processorName -> "tensor g3" in processorName || "gs301" in processorName ->
ProcessInfo("4nm", "三星", "Samsung 4LPP+") ProcessInfo("4nm", "Samsung", "Samsung 4LPP+") // 三星
"tensor g2" in processorName || "gs201" in processorName -> "tensor g2" in processorName || "gs201" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
"tensor g1" in processorName || "gs101" in processorName -> "tensor g1" in processorName || "gs101" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
"tensor" in processorName -> "tensor" in processorName ->
ProcessInfo("5nm", "三星", "Samsung 5LPE") ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
// 华为麒麟 // 华为麒麟
"kirin 9000" in processorName -> "kirin 9000" in processorName ->
ProcessInfo("5nm", "台积电", "TSMC N5") ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电
"kirin 9000e" in processorName -> "kirin 9000e" in processorName ->
ProcessInfo("5nm", "台积电", "TSMC N5") ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电
"kirin 990" in processorName -> "kirin 990" in processorName ->
ProcessInfo("7nm", "台积电", "TSMC N7+") ProcessInfo("7nm", "TSMC", "TSMC N7+") // 台积电
"kirin 980" in processorName -> "kirin 980" in processorName ->
ProcessInfo("7nm", "台积电", "TSMC N7") ProcessInfo("7nm", "TSMC", "TSMC N7") // 台积电
"kirin 810" in processorName -> "kirin 810" in processorName ->
ProcessInfo("7nm", "台积电", "TSMC N7") ProcessInfo("7nm", "TSMC", "TSMC N7") // 台积电
// 苹果 A 系列(参考) // 苹果 A 系列(参考)
"apple a17" in processorName -> "apple a17" in processorName ->
ProcessInfo("3nm", "台积电", "TSMC N3B") ProcessInfo("3nm", "TSMC", "TSMC N3B") // 台积电
"apple a16" in processorName -> "apple a16" in processorName ->
ProcessInfo("4nm", "台积电", "TSMC N4") ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
"apple a15" in processorName -> "apple a15" in processorName ->
ProcessInfo("5nm", "台积电", "TSMC N5P") ProcessInfo("5nm", "TSMC", "TSMC N5P") // 台积电
"apple a14" in processorName -> "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()) { return if (cores.isNotEmpty()) {
cores[0].uarch.name cores[0].uarch.name
} else { } else {
"未知" "Unknown" // 未知
} }
} }
@ -382,7 +439,7 @@ class CpuInfo {
* @return ABI 字符串例如 "arm64-v8a", "armeabi-v7a" * @return ABI 字符串例如 "arm64-v8a", "armeabi-v7a"
*/ */
fun getAbi(): String { 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<Long> {
return (0 until getCoreCount()).map { getMaxFrequency(it) }
}
/**
* 获取所有核心的最小频率列表
* @return 最小频率列表KHz
*/
fun getAllMinFrequencies(): List<Long> {
return (0 until getCoreCount()).map { getMinFrequency(it) }
}
/**
* 获取所有核心的当前频率列表
* @return 当前频率列表KHz
*/
fun getAllCurrentFrequencies(): List<Long> {
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<Double> {
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<Long> {
return getCoresDetailedInfo().map { it.maxFrequency }
}
/**
* 获取所有核心的最小频率列表实时从系统读取
* @return 最小频率列表Hz
*/
fun getCoresMinFrequencies(): List<Long> {
return getCoresDetailedInfo().map { it.minFrequency }
}
/**
* 获取所有核心的当前频率列表实时从系统读取
* @return 当前频率列表Hz
*/
fun getCoresCurrentFrequencies(): List<Long> {
return getCoresDetailedInfo().map { it.currentFrequency }
}
/**
* 获取所有核心的速度度量值列表
* @return 速度度量值列表GHz
*/
fun getCoresSpeedMetrics(): List<Double> {
return getCoresDetailedInfo().map { it.speedMetric }
}
// ==================== 调频器信息 ==================== // ==================== 调频器信息 ====================
/** /**
@ -470,7 +739,7 @@ class CpuInfo {
File("/sys/devices/system/cpu/cpu$coreId/cpufreq/scaling_governor") File("/sys/devices/system/cpu/cpu$coreId/cpufreq/scaling_governor")
.readText().trim() .readText().trim()
} catch (e: Exception) { } catch (e: Exception) {
"未知" "Unknown" // 未知
} }
} }
@ -525,7 +794,7 @@ class CpuInfo {
return try { return try {
File("/proc/cpuinfo").readText() File("/proc/cpuinfo").readText()
} catch (e: Exception) { } catch (e: Exception) {
"无法读取 /proc/cpuinfo" "Unable to read /proc/cpuinfo" // 无法读取 /proc/cpuinfo
} }
} }
@ -569,60 +838,74 @@ class CpuInfo {
val sb = StringBuilder() val sb = StringBuilder()
// 基本信息 // 基本信息
sb.append("=== CPU 基本信息 ===\n") sb.append("=== CPU Basic Info ===\n") // CPU 基本信息
sb.append("处理器名称: ${getProcessorName()}\n") sb.append("Processor Name: ${getProcessorName()}\n") // 处理器名称
sb.append("供应商: ${getVendor()}\n") sb.append("Vendor: ${getVendor()}\n") // 供应商
val processInfo = getProcessInfo() val processInfo = getProcessInfo()
sb.append("制程工艺: ${processInfo.process}\n") sb.append("Process: ${processInfo.process}\n") // 制程工艺
sb.append("代工厂: ${processInfo.foundry}\n") sb.append("Foundry: ${processInfo.foundry}\n") // 代工厂
if (processInfo.node.isNotEmpty()) { if (processInfo.node.isNotEmpty()) {
sb.append("制程节点: ${processInfo.node}\n") sb.append("Process Node: ${processInfo.node}\n") // 制程节点
} }
sb.append("物理核心数: ${getCoreCount()}\n") sb.append("Physical Cores: ${getCoreCount()}\n") // 物理核心数
sb.append("逻辑处理器数: ${getProcessorCount()}\n") sb.append("Logical Processors: ${getProcessorCount()}\n") // 逻辑处理器数
// 大小核信息 // 大小核信息
val clusterInfo = getClusterInfo() val clusterInfo = getClusterInfo()
sb.append("\n=== 大小核配置 ===\n") sb.append("\n=== Core Cluster Configuration ===\n") // 大小核配置
if (clusterInfo.bigCoreCount > 0) { 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) { 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) { 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("\n=== Architecture Info ===\n") // 架构信息
sb.append("架构: ${getAllArchitectures().joinToString(", ")}\n") sb.append("Architecture: ${getAllArchitectures().joinToString(", ")}\n") // 架构
sb.append("ABI: ${getAbi()}\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("\n=== Governor ===\n") // 调频器
sb.append("当前调频器: ${getGovernor(0)}\n") sb.append("Current Governor: ${getGovernor(0)}\n") // 当前调频器
sb.append("可用调频器: ${getAvailableGovernors().joinToString(", ")}\n") sb.append("Available Governors: ${getAvailableGovernors().joinToString(", ")}\n") // 可用调频器
// 核心详细频率 // 核心详细信息(包含实时频率和速度度量)
sb.append("\n=== 核心频率信息 ===\n") sb.append("\n=== Core Detailed Info ===\n") // 核心详细信息
getCoreFrequencies().forEach { freq -> val detailedCores = getCoresDetailedInfo()
sb.append("CPU${freq.coreId}: 当前=${formatFrequency(freq.currentFreq.toULong() * 1000UL)}, ") detailedCores.forEachIndexed { index, coreInfo ->
sb.append("范围=${formatFrequency(freq.minFreq.toULong() * 1000UL)}-${formatFrequency(freq.maxFreq.toULong() * 1000UL)}\n") 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("\n=== Cache Info ===\n") // 缓存信息
sb.append("L1i 缓存: ${l1iCaches.size}\n") sb.append("L1i Cache: ${l1iCaches.size}\n") // L1i 缓存
sb.append("L1d 缓存: ${l1dCaches.size}\n") sb.append("L1d Cache: ${l1dCaches.size}\n") // L1d 缓存
sb.append("L2 缓存: ${l2Caches.size}\n") sb.append("L2 Cache: ${l2Caches.size}\n") // L2 缓存
sb.append("L3 缓存: ${l3Caches.size}\n") sb.append("L3 Cache: ${l3Caches.size}\n") // L3 缓存
// CPU 特性 // CPU 特性
val features = getCpuFeatures() val features = getCpuFeatures()
if (features.isNotEmpty()) { if (features.isNotEmpty()) {
sb.append("\n=== CPU 特性 ===\n") sb.append("\n=== CPU Features ===\n") // CPU 特性
sb.append(features.joinToString(" ")) sb.append(features.joinToString(" "))
sb.append("\n") sb.append("\n")
} }

View File

@ -55,6 +55,14 @@ class DisplayInfo(private val context: Context) {
false false
} }
// 计算屏幕物理尺寸
val screenSize = calculateScreenSize(
displayMetrics.widthPixels,
displayMetrics.heightPixels,
displayMetrics.xdpi,
displayMetrics.ydpi
)
return DefaultDisplayInfo( return DefaultDisplayInfo(
id = defaultDisplay.displayId, id = defaultDisplay.displayId,
name = defaultDisplay.name, name = defaultDisplay.name,
@ -68,7 +76,8 @@ class DisplayInfo(private val context: Context) {
supportedRefreshRates = supportedRefreshRates, supportedRefreshRates = supportedRefreshRates,
isHdr = isHdr, isHdr = isHdr,
hdrTypes, hdrTypes,
isWideColorGamut = isWideColorGamut isWideColorGamut = isWideColorGamut,
screenSize = screenSize
) )
} }
@ -109,6 +118,118 @@ class DisplayInfo(private val context: Context) {
return diagonalPixels / diagonalInches 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 * @property id 显示器 ID
@ -124,6 +245,7 @@ class DisplayInfo(private val context: Context) {
* @property isHdr 是否支持 HDR * @property isHdr 是否支持 HDR
* @property hdrTypes 支持的 HDR 类型列表 * @property hdrTypes 支持的 HDR 类型列表
* @property isWideColorGamut 是否支持广色域 * @property isWideColorGamut 是否支持广色域
* @property screenSize 屏幕物理尺寸
*/ */
data class DefaultDisplayInfo( data class DefaultDisplayInfo(
val id: Int, // 显示器 ID val id: Int, // 显示器 ID
@ -138,6 +260,7 @@ class DisplayInfo(private val context: Context) {
val supportedRefreshRates: List<Float>, // 支持的刷新率列表Hz val supportedRefreshRates: List<Float>, // 支持的刷新率列表Hz
val isHdr: Boolean, // 是否支持 HDR val isHdr: Boolean, // 是否支持 HDR
val hdrTypes: List<String>, // 支持的 HDR 类型列表 val hdrTypes: List<String>, // 支持的 HDR 类型列表
val isWideColorGamut: Boolean // 是否支持广色域 val isWideColorGamut: Boolean, // 是否支持广色域
val screenSize: ScreenSize // 屏幕物理尺寸
) )
} }

View File

@ -21,6 +21,24 @@ class GpuInfo(private val context: Context) {
System.loadLibrary("andinfo") 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 信息 * 获取完整的 GPU 信息
* 包括 Vulkan 物理设备信息和 EGL 信息 * 包括 Vulkan 物理设备信息和 EGL 信息
@ -107,7 +125,24 @@ class GpuInfo(private val context: Context) {
*/ */
fun getOpenGLVersion(): String? { fun getOpenGLVersion(): String? {
val gpuInfo = getGpuInformation() 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 设备类型的中文描述 * 获取 GPU 设备类型的描述
* @return 设备类型中文描述 * @return 设备类型描述
*/ */
fun getDeviceTypeDescription(): String? { fun getDeviceTypeDescription(): String? {
return getDeviceType()?.let { 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 { fun getGpuSummary(): String {
val sb = StringBuilder() val sb = StringBuilder()
val gpuInfo = getGpuInformation() val gpuInfo = getGpuInformation()
val detailedInfo = getGpuDetailedInfo()
sb.append("=== GPU 基本信息 ===\n") sb.append("=== GPU Basic Info ===\n") // GPU 基本信息
getVendorName()?.let { sb.append("供应商: $it\n") } getVendorName()?.let { sb.append("Vendor: $it\n") } // 供应商
getRendererName()?.let { sb.append("型号: $it\n") } getRendererName()?.let { sb.append("Model: $it\n") } // 型号
getDeviceTypeDescription()?.let { sb.append("类型: $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 信息 // Vulkan 信息
if (isVulkanSupported()) { if (isVulkanSupported()) {
sb.append("\n=== Vulkan 信息 ===\n") sb.append("\n=== Vulkan Info ===\n") // Vulkan 信息
sb.append("支持: 是\n") sb.append("Supported: Yes\n") // 支持
getVulkanApiVersion()?.let { sb.append("API 版本: $it\n") } getVulkanApiVersion()?.let { sb.append("API Version: $it\n") } // API 版本
getVulkanDriverVersion()?.let { sb.append("驱动版本: $it\n") } getVulkanDriverVersion()?.let { sb.append("Driver Version: $it\n") } // 驱动版本
gpuInfo.vkPhysicalDevices?.forEach { device -> gpuInfo.vkPhysicalDevices?.forEach { device ->
sb.append("\n--- Vulkan 设备 ---\n") sb.append("\n--- Vulkan Device ---\n") // Vulkan 设备
sb.append("设备名称: ${device.deviceName}\n") sb.append("Device Name: ${device.deviceName}\n") // 设备名称
sb.append("设备 ID: ${device.deviceId}\n") sb.append("Device ID: ${device.deviceId}\n") // 设备 ID
sb.append("供应商 ID: 0x${device.vendorId.toString(16)}\n") sb.append("Vendor ID: 0x${device.vendorId.toString(16)}\n") // 供应商 ID
device.registeredVendorId?.let { 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 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) { if (ver.variant > 0) {
sb.append(" (变体: ${ver.variant})") sb.append(" (Variant: ${ver.variant})") // 变体
} }
sb.append("\n") sb.append("\n")
} }
} else { } else {
sb.append("\n=== Vulkan 信息 ===\n") sb.append("\n=== Vulkan Info ===\n") // Vulkan 信息
sb.append("支持: 否\n") sb.append("Supported: No\n") // 支持
} }
// OpenGL ES 信息 // OpenGL ES 信息
sb.append("\n=== OpenGL ES 信息 ===\n") sb.append("\n=== OpenGL ES Info ===\n") // OpenGL ES 信息
gpuInfo.eglInformation?.glInformation?.let { gl -> gpuInfo.eglInformation?.glInformation?.let { gl ->
gl.glVendor?.let { sb.append("供应商: $it\n") } gl.glVendor?.let { sb.append("Vendor: $it\n") } // 供应商
gl.glRenderer?.let { sb.append("渲染器: $it\n") } gl.glRenderer?.let { sb.append("Renderer: $it\n") } // 渲染器
gl.glVersion?.let { sb.append("版本: $it\n") } gl.glVersion?.let { sb.append("Version: $it\n") } // 版本
val extCount = getOpenGLExtensionCount() val extCount = getOpenGLExtensionCount()
sb.append("扩展数量: $extCount\n") sb.append("Extension Count: $extCount\n") // 扩展数量
} ?: run {
val glVersion = getOpenGLVersion()
sb.append("Version: ${glVersion ?: "Unknown"}\n") // 版本
} }
// EGL 信息 // EGL 信息
sb.append("\n=== EGL 信息 ===\n") sb.append("\n=== EGL Info ===\n") // EGL 信息
gpuInfo.eglInformation?.let { egl -> gpuInfo.eglInformation?.let { egl ->
egl.eglVendor?.let { sb.append("供应商: $it\n") } egl.eglVendor?.let { sb.append("Vendor: $it\n") } // 供应商
egl.eglVersion?.let { sb.append("版本: $it\n") } egl.eglVersion?.let { sb.append("Version: $it\n") } // 版本
egl.eglClientApi?.let { apis -> egl.eglClientApi?.let { apis ->
sb.append("客户端 API: ${apis.joinToString(", ")}\n") sb.append("Client API: ${apis.joinToString(", ")}\n") // 客户端 API
} }
val extCount = getEglExtensionCount() val extCount = getEglExtensionCount()
sb.append("扩展数量: $extCount\n") sb.append("Extension Count: $extCount\n") // 扩展数量
} }
return sb.toString() return sb.toString()
@ -274,7 +638,7 @@ class GpuInfo(private val context: Context) {
* 从注册的 Vulkan 供应商 ID 获取名称 * 从注册的 Vulkan 供应商 ID 获取名称
*/ */
private fun getVendorName(vendorId: VkVendorId): String { 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 物理设备类型映射英文 * Vulkan 物理设备类型映射英文
*/ */
val vkPhysicalDeviceTypeToString = mapOf( val vkPhysicalDeviceTypeToString = mapOf(
VkPhysicalDeviceType.OTHER.value to "Other", VkPhysicalDeviceType.OTHER.value to "Other", // 其他
VkPhysicalDeviceType.INTEGRATED_GPU.value to "Integrated GPU", VkPhysicalDeviceType.INTEGRATED_GPU.value to "Integrated GPU", // 集成显卡
VkPhysicalDeviceType.DISCRETE_GPU.value to "Discrete GPU", VkPhysicalDeviceType.DISCRETE_GPU.value to "Discrete GPU", // 独立显卡
VkPhysicalDeviceType.VIRTUAL_GPU.value to "Virtual 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.CPU.value to "CPU", VkPhysicalDeviceType.CPU.value to "CPU",
) )
@ -314,28 +667,14 @@ class GpuInfo(private val context: Context) {
* Vulkan 注册供应商 ID 映射英文 * Vulkan 注册供应商 ID 映射英文
*/ */
val vkVendorIdToString = mapOf( val vkVendorIdToString = mapOf(
VkVendorId.KHRONOS to "Khronos", VkVendorId.KHRONOS to "Khronos", // Khronos科纳斯
VkVendorId.VIV to "Vivante", VkVendorId.VIV to "Vivante", // Vivante维万特
VkVendorId.VSI to "VeriSilicon", VkVendorId.VSI to "VeriSilicon", // VeriSilicon芯原
VkVendorId.KAZAN to "Kazan", VkVendorId.KAZAN to "Kazan",
VkVendorId.CODEPLAY to "Codeplay", VkVendorId.CODEPLAY to "Codeplay",
VkVendorId.MESA to "Mesa", VkVendorId.MESA to "Mesa",
VkVendorId.POCL to "POCL", VkVendorId.POCL to "POCL",
VkVendorId.MOBILEYE to "Mobileye", VkVendorId.MOBILEYE to "Mobileye", // 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移动眼",
) )
/** /**

View File

@ -9,6 +9,26 @@ import java.io.File
class StorageInfo(private val context: Context) { 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 val internalStorageTotalSpace: Long
get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs -> get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs ->
@ -87,12 +107,150 @@ class StorageInfo(private val context: Context) {
0L 0L
} }
// 系统占用大小 // 系统占用大小/system 分区)
val systemSize: Long val systemSize: Long
get() = StatFs(Environment.getRootDirectory().absolutePath).let { statFs -> get() = StatFs(Environment.getRootDirectory().absolutePath).let { statFs ->
statFs.blockCountLong * statFs.blockSizeLong 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? val externalStorageTotalSpace: Long?
get() = runCatching { get() = runCatching {