Compare commits
No commits in common. "264a45f4db891748a872eda9b4ea536049541970" and "a59073b0af86c954bf1ad70040e642709094cbcd" have entirely different histories.
264a45f4db
...
a59073b0af
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"FSharp.suggestGitignore": false
|
|
||||||
}
|
|
||||||
@ -1,263 +0,0 @@
|
|||||||
# 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
|
|
||||||
- 向后兼容: 所有原有方法保持不变
|
|
||||||
@ -1,523 +0,0 @@
|
|||||||
# 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 布局自适应
|
|
||||||
- 字体大小调整
|
|
||||||
- 图片资源选择
|
|
||||||
- 视频播放优化
|
|
||||||
- 游戏控制布局
|
|
||||||
- 阅读体验优化
|
|
||||||
- 设备分类统计
|
|
||||||
- 用户体验研究
|
|
||||||
@ -1,472 +0,0 @@
|
|||||||
# 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
|
|
||||||
- **入门级**: 其他
|
|
||||||
@ -1,671 +0,0 @@
|
|||||||
# 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 -> "Back" // 后置
|
CameraFacing.BACK -> "后置"
|
||||||
CameraFacing.FRONT -> "Front" // 前置
|
CameraFacing.FRONT -> "前置"
|
||||||
CameraFacing.EXTERNAL -> "External" // 外置
|
CameraFacing.EXTERNAL -> "外置"
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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" // 单色/近红外
|
5 -> "Mono/NIR (单色/近红外)" // MONO/NIR
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 "Unknown" // 未知
|
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "EXTERNAL" else "未知"
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 -> "Off" // 关闭
|
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_OFF -> "关闭"
|
||||||
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE -> "Simple" // 简单
|
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE -> "简单"
|
||||||
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_FULL -> "Full" // 完整
|
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_FULL -> "完整"
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 Capture") // RAW拍摄
|
if (capabilities.contains(CameraCapability.RAW)) features.add("RAW拍摄")
|
||||||
if (capabilities.contains(CameraCapability.BURST_CAPTURE)) features.add("Burst Capture") // 连拍
|
if (capabilities.contains(CameraCapability.BURST_CAPTURE)) features.add("连拍")
|
||||||
if (capabilities.contains(CameraCapability.DEPTH_OUTPUT)) features.add("Depth Output") // 景深输出
|
if (capabilities.contains(CameraCapability.DEPTH_OUTPUT)) features.add("景深输出")
|
||||||
if (capabilities.contains(CameraCapability.CONSTRAINED_HIGH_SPEED_VIDEO)) features.add("High Speed Video") // 高速视频
|
if (capabilities.contains(CameraCapability.CONSTRAINED_HIGH_SPEED_VIDEO)) features.add("高速视频")
|
||||||
if (capabilities.contains(CameraCapability.MANUAL_SENSOR)) features.add("Manual Mode") // 手动模式
|
if (capabilities.contains(CameraCapability.MANUAL_SENSOR)) features.add("手动模式")
|
||||||
if (capabilities.contains(CameraCapability.MONOCHROME)) features.add("Monochrome Mode") // 黑白模式
|
if (capabilities.contains(CameraCapability.MONOCHROME)) features.add("黑白模式")
|
||||||
if (capabilities.contains(CameraCapability.ULTRA_HIGH_RESOLUTION_SENSOR)) features.add("Ultra High Resolution") // 超高分辨率
|
if (capabilities.contains(CameraCapability.ULTRA_HIGH_RESOLUTION_SENSOR)) features.add("超高分辨率")
|
||||||
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("Optical Stabilization") // 光学防抖
|
if (hasOpticalStabilization(characteristics)) features.add("光学防抖")
|
||||||
if (hasVideoStabilization(characteristics)) features.add("Video Stabilization") // 视频防抖
|
if (hasVideoStabilization(characteristics)) features.add("视频防抖")
|
||||||
|
|
||||||
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 -> "Off" // 关闭
|
CameraCharacteristics.CONTROL_AE_MODE_OFF -> "关闭"
|
||||||
CameraCharacteristics.CONTROL_AE_MODE_ON -> "Auto" // 自动
|
CameraCharacteristics.CONTROL_AE_MODE_ON -> "自动"
|
||||||
CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH -> "Auto Flash" // 自动闪光
|
CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH -> "自动闪光"
|
||||||
CameraCharacteristics.CONTROL_AE_MODE_ON_ALWAYS_FLASH -> "Always Flash" // 强制闪光
|
CameraCharacteristics.CONTROL_AE_MODE_ON_ALWAYS_FLASH -> "强制闪光"
|
||||||
CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE -> "Auto Flash Redeye" // 防红眼
|
CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE -> "防红眼"
|
||||||
CameraCharacteristics.CONTROL_AE_MODE_ON_EXTERNAL_FLASH -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "External Flash" else "Unknown" // 外置闪光/未知
|
CameraCharacteristics.CONTROL_AE_MODE_ON_EXTERNAL_FLASH -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "外置闪光" else "未知"
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 -> "Off" // 关闭
|
CameraCharacteristics.CONTROL_AF_MODE_OFF -> "关闭"
|
||||||
CameraCharacteristics.CONTROL_AF_MODE_AUTO -> "Auto" // 自动
|
CameraCharacteristics.CONTROL_AF_MODE_AUTO -> "自动"
|
||||||
CameraCharacteristics.CONTROL_AF_MODE_MACRO -> "Macro" // 微距
|
CameraCharacteristics.CONTROL_AF_MODE_MACRO -> "微距"
|
||||||
CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_VIDEO -> "Continuous Video" // 连续视频
|
CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_VIDEO -> "连续视频"
|
||||||
CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_PICTURE -> "Continuous Picture" // 连续拍照
|
CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_PICTURE -> "连续拍照"
|
||||||
CameraCharacteristics.CONTROL_AF_MODE_EDOF -> "EDOF"
|
CameraCharacteristics.CONTROL_AF_MODE_EDOF -> "EDOF"
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 -> "Off" // 关闭
|
CameraCharacteristics.CONTROL_AWB_MODE_OFF -> "关闭"
|
||||||
CameraCharacteristics.CONTROL_AWB_MODE_AUTO -> "Auto" // 自动
|
CameraCharacteristics.CONTROL_AWB_MODE_AUTO -> "自动"
|
||||||
CameraCharacteristics.CONTROL_AWB_MODE_INCANDESCENT -> "Incandescent" // 白炽灯
|
CameraCharacteristics.CONTROL_AWB_MODE_INCANDESCENT -> "白炽灯"
|
||||||
CameraCharacteristics.CONTROL_AWB_MODE_FLUORESCENT -> "Fluorescent" // 荧光灯
|
CameraCharacteristics.CONTROL_AWB_MODE_FLUORESCENT -> "荧光灯"
|
||||||
CameraCharacteristics.CONTROL_AWB_MODE_WARM_FLUORESCENT -> "Warm Fluorescent" // 暖荧光
|
CameraCharacteristics.CONTROL_AWB_MODE_WARM_FLUORESCENT -> "暖荧光"
|
||||||
CameraCharacteristics.CONTROL_AWB_MODE_DAYLIGHT -> "Daylight" // 日光
|
CameraCharacteristics.CONTROL_AWB_MODE_DAYLIGHT -> "日光"
|
||||||
CameraCharacteristics.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT -> "Cloudy" // 阴天
|
CameraCharacteristics.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT -> "阴天"
|
||||||
CameraCharacteristics.CONTROL_AWB_MODE_TWILIGHT -> "Twilight" // 黄昏
|
CameraCharacteristics.CONTROL_AWB_MODE_TWILIGHT -> "黄昏"
|
||||||
CameraCharacteristics.CONTROL_AWB_MODE_SHADE -> "Shade" // 阴影
|
CameraCharacteristics.CONTROL_AWB_MODE_SHADE -> "阴影"
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 -> "Disabled" // 禁用
|
CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED -> "禁用"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_FACE_PRIORITY -> "Face Priority" // 人像优先
|
CameraCharacteristics.CONTROL_SCENE_MODE_FACE_PRIORITY -> "人像优先"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_ACTION -> "Action" // 运动
|
CameraCharacteristics.CONTROL_SCENE_MODE_ACTION -> "运动"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT -> "Portrait" // 人像
|
CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT -> "人像"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE -> "Landscape" // 风景
|
CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE -> "风景"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT -> "Night" // 夜景
|
CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT -> "夜景"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT -> "Night Portrait" // 夜景人像
|
CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT -> "夜景人像"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE -> "Theatre" // 剧院
|
CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE -> "剧院"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_BEACH -> "Beach" // 海滩
|
CameraCharacteristics.CONTROL_SCENE_MODE_BEACH -> "海滩"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_SNOW -> "Snow" // 雪景
|
CameraCharacteristics.CONTROL_SCENE_MODE_SNOW -> "雪景"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET -> "Sunset" // 日落
|
CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET -> "日落"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO -> "Steady Photo" // 防抖
|
CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO -> "防抖"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS -> "Fireworks" // 烟火
|
CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS -> "烟火"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS -> "Sports" // 体育
|
CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS -> "体育"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_PARTY -> "Party" // 派对
|
CameraCharacteristics.CONTROL_SCENE_MODE_PARTY -> "派对"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT -> "Candlelight" // 烛光
|
CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT -> "烛光"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE -> "Barcode" // 条形码
|
CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE -> "条形码"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) "High Speed Video" else "Unknown" // 高速视频/未知
|
CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) "高速视频" else "未知"
|
||||||
CameraCharacteristics.CONTROL_SCENE_MODE_HDR -> "HDR"
|
CameraCharacteristics.CONTROL_SCENE_MODE_HDR -> "HDR"
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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 -> "Off" // 关闭
|
CameraCharacteristics.CONTROL_EFFECT_MODE_OFF -> "关闭"
|
||||||
CameraCharacteristics.CONTROL_EFFECT_MODE_MONO -> "Mono" // 黑白
|
CameraCharacteristics.CONTROL_EFFECT_MODE_MONO -> "黑白"
|
||||||
CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE -> "Negative" // 负片
|
CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE -> "负片"
|
||||||
CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE -> "Solarize" // 曝光
|
CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE -> "曝光"
|
||||||
CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA -> "Sepia" // 棕褐色
|
CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA -> "棕褐色"
|
||||||
CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE -> "Posterize" // 海报化
|
CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE -> "海报化"
|
||||||
CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD -> "Whiteboard" // 白板
|
CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD -> "白板"
|
||||||
CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD -> "Blackboard" // 黑板
|
CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD -> "黑板"
|
||||||
CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA -> "Aqua" // 水蓝
|
CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA -> "水蓝"
|
||||||
else -> "Unknown" // 未知
|
else -> "未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,63 +32,6 @@ 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 集群列表
|
||||||
@ -157,7 +100,7 @@ class CpuInfo {
|
|||||||
return if (packages.isNotEmpty()) {
|
return if (packages.isNotEmpty()) {
|
||||||
packages[0].name
|
packages[0].name
|
||||||
} else {
|
} else {
|
||||||
"Unknown" // 未知
|
"未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +112,7 @@ class CpuInfo {
|
|||||||
return if (cores.isNotEmpty()) {
|
return if (cores.isNotEmpty()) {
|
||||||
cores[0].vendor.name
|
cores[0].vendor.name
|
||||||
} else {
|
} else {
|
||||||
"Unknown" // 未知
|
"未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +205,7 @@ class CpuInfo {
|
|||||||
/**
|
/**
|
||||||
* 制程信息数据类
|
* 制程信息数据类
|
||||||
* @property process 制程工艺,例如 "4nm", "5nm", "7nm" 等
|
* @property process 制程工艺,例如 "4nm", "5nm", "7nm" 等
|
||||||
* @property foundry 代工厂,例如 "TSMC", "Samsung" 等
|
* @property foundry 代工厂,例如 "台积电", "三星" 等
|
||||||
* @property node 详细制程节点,例如 "TSMC N4P", "Samsung 4LPE" 等
|
* @property node 详细制程节点,例如 "TSMC N4P", "Samsung 4LPE" 等
|
||||||
*/
|
*/
|
||||||
data class ProcessInfo(
|
data class ProcessInfo(
|
||||||
@ -281,110 +224,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", "TSMC N4P") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4P")
|
||||||
"snapdragon 8 gen 2" in processorName || "sm8550" in processorName ->
|
"snapdragon 8 gen 2" in processorName || "sm8550" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
"snapdragon 8 gen 1" in processorName || "sm8450" in processorName ->
|
"snapdragon 8 gen 1" in processorName || "sm8450" in processorName ->
|
||||||
ProcessInfo("4nm", "Samsung", "Samsung 4LPE") // 三星
|
ProcessInfo("4nm", "三星", "Samsung 4LPE")
|
||||||
"snapdragon 888+" in processorName || "sm8350-ab" in processorName ->
|
"snapdragon 888+" in processorName || "sm8350-ab" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
"snapdragon 888" in processorName || "sm8350" in processorName ->
|
"snapdragon 888" in processorName || "sm8350" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
"snapdragon 870" in processorName || "sm8250-ac" in processorName ->
|
"snapdragon 870" in processorName || "sm8250-ac" in processorName ->
|
||||||
ProcessInfo("7nm", "TSMC", "TSMC N7P") // 台积电
|
ProcessInfo("7nm", "台积电", "TSMC N7P")
|
||||||
"snapdragon 865+" in processorName || "sm8250-ab" in processorName ->
|
"snapdragon 865+" in processorName || "sm8250-ab" in processorName ->
|
||||||
ProcessInfo("7nm", "TSMC", "TSMC N7P") // 台积电
|
ProcessInfo("7nm", "台积电", "TSMC N7P")
|
||||||
"snapdragon 865" in processorName || "sm8250" in processorName ->
|
"snapdragon 865" in processorName || "sm8250" in processorName ->
|
||||||
ProcessInfo("7nm", "TSMC", "TSMC N7P") // 台积电
|
ProcessInfo("7nm", "台积电", "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", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
"snapdragon 778g" in processorName || "sm7325" in processorName ->
|
"snapdragon 778g" in processorName || "sm7325" in processorName ->
|
||||||
ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
|
ProcessInfo("6nm", "台积电", "TSMC N6")
|
||||||
|
|
||||||
// 高通 Snapdragon 6 系列
|
// 高通 Snapdragon 6 系列
|
||||||
"snapdragon 695" in processorName || "sm6375" in processorName ->
|
"snapdragon 695" in processorName || "sm6375" in processorName ->
|
||||||
ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
|
ProcessInfo("6nm", "台积电", "TSMC N6")
|
||||||
|
|
||||||
// 联发科 Dimensity 9000 系列
|
// 联发科 Dimensity 9000 系列
|
||||||
"dimensity 9300" in processorName || "mt6989" in processorName ->
|
"dimensity 9300" in processorName || "mt6989" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4P") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4P")
|
||||||
"dimensity 9200+" in processorName || "mt6985" in processorName ->
|
"dimensity 9200+" in processorName || "mt6985" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
"dimensity 9200" in processorName || "mt6983" in processorName ->
|
"dimensity 9200" in processorName || "mt6983" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
"dimensity 9000+" in processorName || "mt6985" in processorName ->
|
"dimensity 9000+" in processorName || "mt6985" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
"dimensity 9000" in processorName || "mt6983" in processorName ->
|
"dimensity 9000" in processorName || "mt6983" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
|
|
||||||
// 联发科 Dimensity 8000 系列
|
// 联发科 Dimensity 8000 系列
|
||||||
"dimensity 8300" in processorName || "mt6897" in processorName ->
|
"dimensity 8300" in processorName || "mt6897" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
"dimensity 8200" in processorName || "mt6896" in processorName ->
|
"dimensity 8200" in processorName || "mt6896" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
"dimensity 8100" in processorName || "mt6895" in processorName ->
|
"dimensity 8100" in processorName || "mt6895" in processorName ->
|
||||||
ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电
|
ProcessInfo("5nm", "台积电", "TSMC N5")
|
||||||
|
|
||||||
// 联发科 Dimensity 1000 系列
|
// 联发科 Dimensity 1000 系列
|
||||||
"dimensity 1200" in processorName || "mt6893" in processorName ->
|
"dimensity 1200" in processorName || "mt6893" in processorName ->
|
||||||
ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
|
ProcessInfo("6nm", "台积电", "TSMC N6")
|
||||||
"dimensity 1080" in processorName || "mt6877" in processorName ->
|
"dimensity 1080" in processorName || "mt6877" in processorName ->
|
||||||
ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
|
ProcessInfo("6nm", "台积电", "TSMC N6")
|
||||||
|
|
||||||
// 联发科 Helio 系列
|
// 联发科 Helio 系列
|
||||||
"helio g99" in processorName || "mt6789" in processorName ->
|
"helio g99" in processorName || "mt6789" in processorName ->
|
||||||
ProcessInfo("6nm", "TSMC", "TSMC N6") // 台积电
|
ProcessInfo("6nm", "台积电", "TSMC N6")
|
||||||
|
|
||||||
// 三星 Exynos
|
// 三星 Exynos
|
||||||
"exynos 2400" in processorName || "s5e9945" in processorName ->
|
"exynos 2400" in processorName || "s5e9945" in processorName ->
|
||||||
ProcessInfo("4nm", "Samsung", "Samsung 4LPP+") // 三星
|
ProcessInfo("4nm", "三星", "Samsung 4LPP+")
|
||||||
"exynos 2200" in processorName || "s5e9925" in processorName ->
|
"exynos 2200" in processorName || "s5e9925" in processorName ->
|
||||||
ProcessInfo("4nm", "Samsung", "Samsung 4LPE") // 三星
|
ProcessInfo("4nm", "三星", "Samsung 4LPE")
|
||||||
"exynos 2100" in processorName || "s5e9840" in processorName ->
|
"exynos 2100" in processorName || "s5e9840" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
"exynos 1080" in processorName || "s5e1080" in processorName ->
|
"exynos 1080" in processorName || "s5e1080" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
"exynos 1380" in processorName || "s5e8835" in processorName ->
|
"exynos 1380" in processorName || "s5e8835" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
"exynos 1280" in processorName || "s5e8825" in processorName ->
|
"exynos 1280" in processorName || "s5e8825" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
|
|
||||||
// 谷歌 Tensor
|
// 谷歌 Tensor
|
||||||
"tensor g3" in processorName || "gs301" in processorName ->
|
"tensor g3" in processorName || "gs301" in processorName ->
|
||||||
ProcessInfo("4nm", "Samsung", "Samsung 4LPP+") // 三星
|
ProcessInfo("4nm", "三星", "Samsung 4LPP+")
|
||||||
"tensor g2" in processorName || "gs201" in processorName ->
|
"tensor g2" in processorName || "gs201" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
"tensor g1" in processorName || "gs101" in processorName ->
|
"tensor g1" in processorName || "gs101" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
"tensor" in processorName ->
|
"tensor" in processorName ->
|
||||||
ProcessInfo("5nm", "Samsung", "Samsung 5LPE") // 三星
|
ProcessInfo("5nm", "三星", "Samsung 5LPE")
|
||||||
|
|
||||||
// 华为麒麟
|
// 华为麒麟
|
||||||
"kirin 9000" in processorName ->
|
"kirin 9000" in processorName ->
|
||||||
ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电
|
ProcessInfo("5nm", "台积电", "TSMC N5")
|
||||||
"kirin 9000e" in processorName ->
|
"kirin 9000e" in processorName ->
|
||||||
ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电
|
ProcessInfo("5nm", "台积电", "TSMC N5")
|
||||||
"kirin 990" in processorName ->
|
"kirin 990" in processorName ->
|
||||||
ProcessInfo("7nm", "TSMC", "TSMC N7+") // 台积电
|
ProcessInfo("7nm", "台积电", "TSMC N7+")
|
||||||
"kirin 980" in processorName ->
|
"kirin 980" in processorName ->
|
||||||
ProcessInfo("7nm", "TSMC", "TSMC N7") // 台积电
|
ProcessInfo("7nm", "台积电", "TSMC N7")
|
||||||
"kirin 810" in processorName ->
|
"kirin 810" in processorName ->
|
||||||
ProcessInfo("7nm", "TSMC", "TSMC N7") // 台积电
|
ProcessInfo("7nm", "台积电", "TSMC N7")
|
||||||
|
|
||||||
// 苹果 A 系列(参考)
|
// 苹果 A 系列(参考)
|
||||||
"apple a17" in processorName ->
|
"apple a17" in processorName ->
|
||||||
ProcessInfo("3nm", "TSMC", "TSMC N3B") // 台积电
|
ProcessInfo("3nm", "台积电", "TSMC N3B")
|
||||||
"apple a16" in processorName ->
|
"apple a16" in processorName ->
|
||||||
ProcessInfo("4nm", "TSMC", "TSMC N4") // 台积电
|
ProcessInfo("4nm", "台积电", "TSMC N4")
|
||||||
"apple a15" in processorName ->
|
"apple a15" in processorName ->
|
||||||
ProcessInfo("5nm", "TSMC", "TSMC N5P") // 台积电
|
ProcessInfo("5nm", "台积电", "TSMC N5P")
|
||||||
"apple a14" in processorName ->
|
"apple a14" in processorName ->
|
||||||
ProcessInfo("5nm", "TSMC", "TSMC N5") // 台积电
|
ProcessInfo("5nm", "台积电", "TSMC N5")
|
||||||
|
|
||||||
// 默认情况
|
// 默认情况
|
||||||
else -> ProcessInfo("Unknown", "Unknown", "") // 未知
|
else -> ProcessInfo("未知", "未知", "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,7 +363,7 @@ class CpuInfo {
|
|||||||
return if (cores.isNotEmpty()) {
|
return if (cores.isNotEmpty()) {
|
||||||
cores[0].uarch.name
|
cores[0].uarch.name
|
||||||
} else {
|
} else {
|
||||||
"Unknown" // 未知
|
"未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +382,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() ?: "Unknown" // 未知
|
return Build.SUPPORTED_ABIS.firstOrNull() ?: "未知"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -515,218 +458,6 @@ 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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 调频器信息 ====================
|
// ==================== 调频器信息 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -739,7 +470,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" // 未知
|
"未知"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,7 +525,7 @@ class CpuInfo {
|
|||||||
return try {
|
return try {
|
||||||
File("/proc/cpuinfo").readText()
|
File("/proc/cpuinfo").readText()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
"Unable to read /proc/cpuinfo" // 无法读取 /proc/cpuinfo
|
"无法读取 /proc/cpuinfo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,74 +569,60 @@ class CpuInfo {
|
|||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
|
|
||||||
// 基本信息
|
// 基本信息
|
||||||
sb.append("=== CPU Basic Info ===\n") // CPU 基本信息
|
sb.append("=== CPU 基本信息 ===\n")
|
||||||
sb.append("Processor Name: ${getProcessorName()}\n") // 处理器名称
|
sb.append("处理器名称: ${getProcessorName()}\n")
|
||||||
sb.append("Vendor: ${getVendor()}\n") // 供应商
|
sb.append("供应商: ${getVendor()}\n")
|
||||||
val processInfo = getProcessInfo()
|
val processInfo = getProcessInfo()
|
||||||
sb.append("Process: ${processInfo.process}\n") // 制程工艺
|
sb.append("制程工艺: ${processInfo.process}\n")
|
||||||
sb.append("Foundry: ${processInfo.foundry}\n") // 代工厂
|
sb.append("代工厂: ${processInfo.foundry}\n")
|
||||||
if (processInfo.node.isNotEmpty()) {
|
if (processInfo.node.isNotEmpty()) {
|
||||||
sb.append("Process Node: ${processInfo.node}\n") // 制程节点
|
sb.append("制程节点: ${processInfo.node}\n")
|
||||||
}
|
}
|
||||||
sb.append("Physical Cores: ${getCoreCount()}\n") // 物理核心数
|
sb.append("物理核心数: ${getCoreCount()}\n")
|
||||||
sb.append("Logical Processors: ${getProcessorCount()}\n") // 逻辑处理器数
|
sb.append("逻辑处理器数: ${getProcessorCount()}\n")
|
||||||
|
|
||||||
// 大小核信息
|
// 大小核信息
|
||||||
val clusterInfo = getClusterInfo()
|
val clusterInfo = getClusterInfo()
|
||||||
sb.append("\n=== Core Cluster Configuration ===\n") // 大小核配置
|
sb.append("\n=== 大小核配置 ===\n")
|
||||||
if (clusterInfo.bigCoreCount > 0) {
|
if (clusterInfo.bigCoreCount > 0) {
|
||||||
sb.append("Big Cores: ${clusterInfo.bigCoreCount}, Max Frequency: ${formatFrequency(clusterInfo.bigCoreFreq)}\n") // 大核
|
sb.append("大核: ${clusterInfo.bigCoreCount} 个, 最高频率: ${formatFrequency(clusterInfo.bigCoreFreq)}\n")
|
||||||
}
|
}
|
||||||
if (clusterInfo.midCoreCount > 0) {
|
if (clusterInfo.midCoreCount > 0) {
|
||||||
sb.append("Mid Cores: ${clusterInfo.midCoreCount}, Max Frequency: ${formatFrequency(clusterInfo.midCoreFreq)}\n") // 中核
|
sb.append("中核: ${clusterInfo.midCoreCount} 个, 最高频率: ${formatFrequency(clusterInfo.midCoreFreq)}\n")
|
||||||
}
|
}
|
||||||
if (clusterInfo.littleCoreCount > 0) {
|
if (clusterInfo.littleCoreCount > 0) {
|
||||||
sb.append("Little Cores: ${clusterInfo.littleCoreCount}, Max Frequency: ${formatFrequency(clusterInfo.littleCoreFreq)}\n") // 小核
|
sb.append("小核: ${clusterInfo.littleCoreCount} 个, 最高频率: ${formatFrequency(clusterInfo.littleCoreFreq)}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 架构信息
|
// 架构信息
|
||||||
sb.append("\n=== Architecture Info ===\n") // 架构信息
|
sb.append("\n=== 架构信息 ===\n")
|
||||||
sb.append("Architecture: ${getAllArchitectures().joinToString(", ")}\n") // 架构
|
sb.append("架构: ${getAllArchitectures().joinToString(", ")}\n")
|
||||||
sb.append("ABI: ${getAbi()}\n")
|
sb.append("ABI: ${getAbi()}\n")
|
||||||
sb.append("Supported ABIs: ${getSupportedAbis().joinToString(", ")}\n") // 支持的 ABI
|
sb.append("支持的 ABI: ${getSupportedAbis().joinToString(", ")}\n")
|
||||||
|
|
||||||
// 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=== Governor ===\n") // 调频器
|
sb.append("\n=== 调频器 ===\n")
|
||||||
sb.append("Current Governor: ${getGovernor(0)}\n") // 当前调频器
|
sb.append("当前调频器: ${getGovernor(0)}\n")
|
||||||
sb.append("Available Governors: ${getAvailableGovernors().joinToString(", ")}\n") // 可用调频器
|
sb.append("可用调频器: ${getAvailableGovernors().joinToString(", ")}\n")
|
||||||
|
|
||||||
// 核心详细信息(包含实时频率和速度度量)
|
// 核心详细频率
|
||||||
sb.append("\n=== Core Detailed Info ===\n") // 核心详细信息
|
sb.append("\n=== 核心频率信息 ===\n")
|
||||||
val detailedCores = getCoresDetailedInfo()
|
getCoreFrequencies().forEach { freq ->
|
||||||
detailedCores.forEachIndexed { index, coreInfo ->
|
sb.append("CPU${freq.coreId}: 当前=${formatFrequency(freq.currentFreq.toULong() * 1000UL)}, ")
|
||||||
sb.append("CPU$index: ")
|
sb.append("范围=${formatFrequency(freq.minFreq.toULong() * 1000UL)}-${formatFrequency(freq.maxFreq.toULong() * 1000UL)}\n")
|
||||||
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=== Cache Info ===\n") // 缓存信息
|
sb.append("\n=== 缓存信息 ===\n")
|
||||||
sb.append("L1i Cache: ${l1iCaches.size}\n") // L1i 缓存
|
sb.append("L1i 缓存: ${l1iCaches.size} 个\n")
|
||||||
sb.append("L1d Cache: ${l1dCaches.size}\n") // L1d 缓存
|
sb.append("L1d 缓存: ${l1dCaches.size} 个\n")
|
||||||
sb.append("L2 Cache: ${l2Caches.size}\n") // L2 缓存
|
sb.append("L2 缓存: ${l2Caches.size} 个\n")
|
||||||
sb.append("L3 Cache: ${l3Caches.size}\n") // L3 缓存
|
sb.append("L3 缓存: ${l3Caches.size} 个\n")
|
||||||
|
|
||||||
// CPU 特性
|
// CPU 特性
|
||||||
val features = getCpuFeatures()
|
val features = getCpuFeatures()
|
||||||
if (features.isNotEmpty()) {
|
if (features.isNotEmpty()) {
|
||||||
sb.append("\n=== CPU Features ===\n") // CPU 特性
|
sb.append("\n=== CPU 特性 ===\n")
|
||||||
sb.append(features.joinToString(" "))
|
sb.append(features.joinToString(" "))
|
||||||
sb.append("\n")
|
sb.append("\n")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,14 +55,6 @@ 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,
|
||||||
@ -76,8 +68,7 @@ class DisplayInfo(private val context: Context) {
|
|||||||
supportedRefreshRates = supportedRefreshRates,
|
supportedRefreshRates = supportedRefreshRates,
|
||||||
isHdr = isHdr,
|
isHdr = isHdr,
|
||||||
hdrTypes,
|
hdrTypes,
|
||||||
isWideColorGamut = isWideColorGamut,
|
isWideColorGamut = isWideColorGamut
|
||||||
screenSize = screenSize
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,118 +109,6 @@ 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
|
||||||
@ -245,7 +124,6 @@ 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
|
||||||
@ -260,7 +138,6 @@ 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,24 +21,6 @@ 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 信息
|
||||||
@ -125,24 +107,7 @@ class GpuInfo(private val context: Context) {
|
|||||||
*/
|
*/
|
||||||
fun getOpenGLVersion(): String? {
|
fun getOpenGLVersion(): String? {
|
||||||
val gpuInfo = getGpuInformation()
|
val gpuInfo = getGpuInformation()
|
||||||
val glVersion = gpuInfo.eglInformation?.glInformation?.glVersion
|
return 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,328 +172,12 @@ class GpuInfo(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 GPU 设备类型的描述
|
* 获取 GPU 设备类型的中文描述
|
||||||
* @return 设备类型描述
|
* @return 设备类型中文描述
|
||||||
*/
|
*/
|
||||||
fun getDeviceTypeDescription(): String? {
|
fun getDeviceTypeDescription(): String? {
|
||||||
return getDeviceType()?.let {
|
return getDeviceType()?.let {
|
||||||
vkPhysicalDeviceTypeToString[it.value] // 使用英文
|
vkPhysicalDeviceTypeToStringChinese[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
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,73 +188,60 @@ 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 Basic Info ===\n") // GPU 基本信息
|
sb.append("=== GPU 基本信息 ===\n")
|
||||||
getVendorName()?.let { sb.append("Vendor: $it\n") } // 供应商
|
getVendorName()?.let { sb.append("供应商: $it\n") }
|
||||||
getRendererName()?.let { sb.append("Model: $it\n") } // 型号
|
getRendererName()?.let { sb.append("型号: $it\n") }
|
||||||
getDeviceTypeDescription()?.let { sb.append("Type: $it\n") } // 类型
|
getDeviceTypeDescription()?.let { sb.append("类型: $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 Info ===\n") // Vulkan 信息
|
sb.append("\n=== Vulkan 信息 ===\n")
|
||||||
sb.append("Supported: Yes\n") // 支持
|
sb.append("支持: 是\n")
|
||||||
getVulkanApiVersion()?.let { sb.append("API Version: $it\n") } // API 版本
|
getVulkanApiVersion()?.let { sb.append("API 版本: $it\n") }
|
||||||
getVulkanDriverVersion()?.let { sb.append("Driver Version: $it\n") } // 驱动版本
|
getVulkanDriverVersion()?.let { sb.append("驱动版本: $it\n") }
|
||||||
|
|
||||||
gpuInfo.vkPhysicalDevices?.forEach { device ->
|
gpuInfo.vkPhysicalDevices?.forEach { device ->
|
||||||
sb.append("\n--- Vulkan Device ---\n") // Vulkan 设备
|
sb.append("\n--- Vulkan 设备 ---\n")
|
||||||
sb.append("Device Name: ${device.deviceName}\n") // 设备名称
|
sb.append("设备名称: ${device.deviceName}\n")
|
||||||
sb.append("Device ID: ${device.deviceId}\n") // 设备 ID
|
sb.append("设备 ID: ${device.deviceId}\n")
|
||||||
sb.append("Vendor ID: 0x${device.vendorId.toString(16)}\n") // 供应商 ID
|
sb.append("供应商 ID: 0x${device.vendorId.toString(16)}\n")
|
||||||
device.registeredVendorId?.let {
|
device.registeredVendorId?.let {
|
||||||
sb.append("Registered Vendor: ${getVendorName(it)}\n") // 注册供应商
|
sb.append("注册供应商: ${getVendorName(it)}\n")
|
||||||
}
|
}
|
||||||
sb.append("Device Type: ${vkPhysicalDeviceTypeToString[device.deviceType.value]}\n") // 设备类型
|
sb.append("设备类型: ${vkPhysicalDeviceTypeToStringChinese[device.deviceType.value]}\n")
|
||||||
val ver = device.apiVersion
|
val ver = device.apiVersion
|
||||||
sb.append("API Version: ${ver.major}.${ver.minor}.${ver.patch}") // API 版本
|
sb.append("API 版本: ${ver.major}.${ver.minor}.${ver.patch}")
|
||||||
if (ver.variant > 0) {
|
if (ver.variant > 0) {
|
||||||
sb.append(" (Variant: ${ver.variant})") // 变体
|
sb.append(" (变体: ${ver.variant})")
|
||||||
}
|
}
|
||||||
sb.append("\n")
|
sb.append("\n")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sb.append("\n=== Vulkan Info ===\n") // Vulkan 信息
|
sb.append("\n=== Vulkan 信息 ===\n")
|
||||||
sb.append("Supported: No\n") // 支持
|
sb.append("支持: 否\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenGL ES 信息
|
// OpenGL ES 信息
|
||||||
sb.append("\n=== OpenGL ES Info ===\n") // OpenGL ES 信息
|
sb.append("\n=== OpenGL ES 信息 ===\n")
|
||||||
gpuInfo.eglInformation?.glInformation?.let { gl ->
|
gpuInfo.eglInformation?.glInformation?.let { gl ->
|
||||||
gl.glVendor?.let { sb.append("Vendor: $it\n") } // 供应商
|
gl.glVendor?.let { sb.append("供应商: $it\n") }
|
||||||
gl.glRenderer?.let { sb.append("Renderer: $it\n") } // 渲染器
|
gl.glRenderer?.let { sb.append("渲染器: $it\n") }
|
||||||
gl.glVersion?.let { sb.append("Version: $it\n") } // 版本
|
gl.glVersion?.let { sb.append("版本: $it\n") }
|
||||||
val extCount = getOpenGLExtensionCount()
|
val extCount = getOpenGLExtensionCount()
|
||||||
sb.append("Extension Count: $extCount\n") // 扩展数量
|
sb.append("扩展数量: $extCount\n")
|
||||||
} ?: run {
|
|
||||||
val glVersion = getOpenGLVersion()
|
|
||||||
sb.append("Version: ${glVersion ?: "Unknown"}\n") // 版本
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EGL 信息
|
// EGL 信息
|
||||||
sb.append("\n=== EGL Info ===\n") // EGL 信息
|
sb.append("\n=== EGL 信息 ===\n")
|
||||||
gpuInfo.eglInformation?.let { egl ->
|
gpuInfo.eglInformation?.let { egl ->
|
||||||
egl.eglVendor?.let { sb.append("Vendor: $it\n") } // 供应商
|
egl.eglVendor?.let { sb.append("供应商: $it\n") }
|
||||||
egl.eglVersion?.let { sb.append("Version: $it\n") } // 版本
|
egl.eglVersion?.let { sb.append("版本: $it\n") }
|
||||||
egl.eglClientApi?.let { apis ->
|
egl.eglClientApi?.let { apis ->
|
||||||
sb.append("Client API: ${apis.joinToString(", ")}\n") // 客户端 API
|
sb.append("客户端 API: ${apis.joinToString(", ")}\n")
|
||||||
}
|
}
|
||||||
val extCount = getEglExtensionCount()
|
val extCount = getEglExtensionCount()
|
||||||
sb.append("Extension Count: $extCount\n") // 扩展数量
|
sb.append("扩展数量: $extCount\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
@ -638,7 +274,7 @@ class GpuInfo(private val context: Context) {
|
|||||||
* 从注册的 Vulkan 供应商 ID 获取名称
|
* 从注册的 Vulkan 供应商 ID 获取名称
|
||||||
*/
|
*/
|
||||||
private fun getVendorName(vendorId: VkVendorId): String {
|
private fun getVendorName(vendorId: VkVendorId): String {
|
||||||
return vkVendorIdToString[vendorId] ?: "Unknown" // 未知
|
return vkVendorIdToStringChinese[vendorId] ?: vkVendorIdToString[vendorId] ?: "Unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -656,10 +292,21 @@ 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",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -667,14 +314,28 @@ class GpuInfo(private val context: Context) {
|
|||||||
* Vulkan 注册供应商 ID 映射(英文)
|
* Vulkan 注册供应商 ID 映射(英文)
|
||||||
*/
|
*/
|
||||||
val vkVendorIdToString = mapOf(
|
val vkVendorIdToString = mapOf(
|
||||||
VkVendorId.KHRONOS to "Khronos", // Khronos(科纳斯)
|
VkVendorId.KHRONOS to "Khronos",
|
||||||
VkVendorId.VIV to "Vivante", // Vivante(维万特)
|
VkVendorId.VIV to "Vivante",
|
||||||
VkVendorId.VSI to "VeriSilicon", // VeriSilicon(芯原)
|
VkVendorId.VSI to "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", // Mobileye(移动眼)
|
VkVendorId.MOBILEYE to "Mobileye",
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vulkan 注册供应商 ID 映射(中文)
|
||||||
|
*/
|
||||||
|
val vkVendorIdToStringChinese = mapOf(
|
||||||
|
VkVendorId.KHRONOS to "Khronos(科纳斯)",
|
||||||
|
VkVendorId.VIV to "Vivante(维万特)",
|
||||||
|
VkVendorId.VSI to "VeriSilicon(芯原)",
|
||||||
|
VkVendorId.KAZAN to "Kazan",
|
||||||
|
VkVendorId.CODEPLAY to "Codeplay",
|
||||||
|
VkVendorId.MESA to "Mesa",
|
||||||
|
VkVendorId.POCL to "POCL",
|
||||||
|
VkVendorId.MOBILEYE to "Mobileye(移动眼)",
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -9,26 +9,6 @@ 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 ->
|
||||||
@ -107,150 +87,12 @@ 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