修改
This commit is contained in:
parent
5eb9cf3ae5
commit
6374b15a31
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"FSharp.suggestGitignore": false
|
||||||
|
}
|
||||||
263
CpuInfo核心详细信息使用示例.md
Normal file
263
CpuInfo核心详细信息使用示例.md
Normal 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
|
||||||
|
- 向后兼容: 所有原有方法保持不变
|
||||||
523
DisplayInfo屏幕尺寸使用示例.md
Normal file
523
DisplayInfo屏幕尺寸使用示例.md
Normal 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 布局自适应
|
||||||
|
- 字体大小调整
|
||||||
|
- 图片资源选择
|
||||||
|
- 视频播放优化
|
||||||
|
- 游戏控制布局
|
||||||
|
- 阅读体验优化
|
||||||
|
- 设备分类统计
|
||||||
|
- 用户体验研究
|
||||||
472
GpuInfo增强功能使用示例.md
Normal file
472
GpuInfo增强功能使用示例.md
Normal 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
671
StorageInfo使用示例.md
Normal 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. **用户提醒**: 低存储空间警告
|
||||||
@ -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" // 未知
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 // 屏幕物理尺寸
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(移动眼)",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user