存储信息修改

This commit is contained in:
xsean 2025-12-23 11:26:42 +08:00
parent a43fcad558
commit 5239088041

View File

@ -5,22 +5,27 @@ import android.os.Environment
import android.os.StatFs import android.os.StatFs
import com.xyzshell.andinfo.libs.storage.models.EncryptionType import com.xyzshell.andinfo.libs.storage.models.EncryptionType
import com.xyzshell.andinfo.utils.SystemProperties import com.xyzshell.andinfo.utils.SystemProperties
import java.io.File
class StorageInfo(private val context: Context) { class StorageInfo(private val context: Context) {
// 内部存储总空间
val internalStorageTotalSpace: Long val internalStorageTotalSpace: Long
get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs -> get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs ->
statFs.blockCountLong * statFs.blockSizeLong statFs.blockCountLong * statFs.blockSizeLong
} }
// 内部存储可用空间
val internalStorageAvailableSpace: Long val internalStorageAvailableSpace: Long
get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs -> get() = StatFs(Environment.getDataDirectory().absolutePath).let { statFs ->
statFs.availableBlocksLong * statFs.blockSizeLong statFs.availableBlocksLong * statFs.blockSizeLong
} }
// 内部存储已使用空间
val internalStorageUsedSpace: Long val internalStorageUsedSpace: Long
get() = internalStorageTotalSpace - internalStorageAvailableSpace get() = internalStorageTotalSpace - internalStorageAvailableSpace
// 内部存储是否加密
val isInternalStorageEncrypted: Boolean? val isInternalStorageEncrypted: Boolean?
get() = when (SystemProperties.getString("ro.crypto.state", "unknown")) { get() = when (SystemProperties.getString("ro.crypto.state", "unknown")) {
"encrypted" -> true "encrypted" -> true
@ -28,6 +33,7 @@ class StorageInfo(private val context: Context) {
else -> null else -> null
} }
// 内部存储加密类型
val internalStorageEncryptionType: EncryptionType? val internalStorageEncryptionType: EncryptionType?
get() = when (SystemProperties.getString("ro.crypto.type", "unknown")) { get() = when (SystemProperties.getString("ro.crypto.type", "unknown")) {
"none" -> EncryptionType.NONE "none" -> EncryptionType.NONE
@ -36,6 +42,58 @@ class StorageInfo(private val context: Context) {
else -> null else -> null
} }
// 内部存储文件系统类型
val internalStorageFileSystemType: String?
get() = try {
// 方法1: 读取 /proc/mounts 文件
File("/proc/mounts").readLines()
.find { it.contains(" /data ") }
?.split("\\s+".toRegex())
?.getOrNull(2)
?: run {
// 方法2: 使用 StatFs (Android 8.0+)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
val statFs = StatFs("/data")
statFs.javaClass.getMethod("getFileSystemName").invoke(statFs) as? String
} else {
null
}
}
} catch (e: Exception) {
null
}
// /data 目录总大小
val dataDirectoryTotalSpace: Long
get() = StatFs("/data").let { statFs ->
statFs.blockCountLong * statFs.blockSizeLong
}
// /data 目录已使用空间
val dataDirectoryUsedSpace: Long
get() = StatFs("/data").let { statFs ->
val total = statFs.blockCountLong * statFs.blockSizeLong
val available = statFs.availableBlocksLong * statFs.blockSizeLong
total - available
}
// 应用程序和数据占用大小
val applicationsAndDataSize: Long
get() = try {
val dataDir = File("/data/data")
val appDir = File("/data/app")
calculateDirectorySize(dataDir) + calculateDirectorySize(appDir)
} catch (e: Exception) {
0L
}
// 系统占用大小
val systemSize: Long
get() = StatFs(Environment.getRootDirectory().absolutePath).let { statFs ->
statFs.blockCountLong * statFs.blockSizeLong
}
// 外部存储总空间
val externalStorageTotalSpace: Long? val externalStorageTotalSpace: Long?
get() = runCatching { get() = runCatching {
StatFs(Environment.getExternalStorageDirectory().absolutePath).let { statFs -> StatFs(Environment.getExternalStorageDirectory().absolutePath).let { statFs ->
@ -43,6 +101,7 @@ class StorageInfo(private val context: Context) {
} }
}.getOrNull() }.getOrNull()
// 外部存储可用空间
val externalStorageAvailableSpace: Long? val externalStorageAvailableSpace: Long?
get() = runCatching { get() = runCatching {
StatFs(Environment.getExternalStorageDirectory().absolutePath).let { statFs -> StatFs(Environment.getExternalStorageDirectory().absolutePath).let { statFs ->
@ -50,6 +109,7 @@ class StorageInfo(private val context: Context) {
} }
}.getOrNull() }.getOrNull()
// 外部存储已使用空间
val externalStorageUsedSpace: Long? val externalStorageUsedSpace: Long?
get() = externalStorageTotalSpace?.let { total -> get() = externalStorageTotalSpace?.let { total ->
externalStorageAvailableSpace?.let { available -> externalStorageAvailableSpace?.let { available ->
@ -57,36 +117,76 @@ class StorageInfo(private val context: Context) {
} }
} }
// 外部存储是否为模拟存储
val isExternalStorageEmulated: Boolean val isExternalStorageEmulated: Boolean
get() = Environment.isExternalStorageEmulated() get() = Environment.isExternalStorageEmulated()
// 外部存储是否可移除
val isExternalStorageRemovable: Boolean val isExternalStorageRemovable: Boolean
get() = Environment.isExternalStorageRemovable() get() = Environment.isExternalStorageRemovable()
// 是否支持可更新的 APEX
val hasUpdatableApex: Boolean? val hasUpdatableApex: Boolean?
get() = SystemProperties.getBoolean("ro.apex.updatable") get() = SystemProperties.getBoolean("ro.apex.updatable")
// 是否使用 system-as-root 分区方案
val usesSystemAsRoot: Boolean? val usesSystemAsRoot: Boolean?
get() = SystemProperties.getBoolean("ro.build.system_root_image") get() = SystemProperties.getBoolean("ro.build.system_root_image")
// 是否使用 A/B 分区更新方案
val usesAb: Boolean? val usesAb: Boolean?
get() = SystemProperties.getBoolean("ro.build.ab_update") get() = SystemProperties.getBoolean("ro.build.ab_update")
// A/B OTA 分区列表
val abOtaPartitions: Array<String>? val abOtaPartitions: Array<String>?
get() = SystemProperties.getString("ro.product.ab_ota_partitions")?.split(",")?.toTypedArray() get() = SystemProperties.getString("ro.product.ab_ota_partitions")?.split(",")?.toTypedArray()
// 是否使用动态分区
val usesDynamicPartitions: Boolean? val usesDynamicPartitions: Boolean?
get() = SystemProperties.getBoolean("ro.boot.dynamic_partitions") get() = SystemProperties.getBoolean("ro.boot.dynamic_partitions")
// 是否使用改造的动态分区
val usesRetrofittedDynamicPartitions: Boolean? val usesRetrofittedDynamicPartitions: Boolean?
get() = SystemProperties.getBoolean("ro.boot.dynamic_partitions_retrofit") get() = SystemProperties.getBoolean("ro.boot.dynamic_partitions_retrofit")
// 是否使用虚拟 A/B 分区
val usesVirtualAb: Boolean? val usesVirtualAb: Boolean?
get() = SystemProperties.getBoolean("ro.virtual_ab.enabled") get() = SystemProperties.getBoolean("ro.virtual_ab.enabled")
// 是否使用改造的虚拟 A/B 分区
val usesRetrofittedVirtualAb: Boolean? val usesRetrofittedVirtualAb: Boolean?
get() = SystemProperties.getBoolean("ro.virtual_ab.retrofit") get() = SystemProperties.getBoolean("ro.virtual_ab.retrofit")
// 虚拟 A/B 分区是否启用压缩
val usesCompressedVirtualAb: Boolean? val usesCompressedVirtualAb: Boolean?
get() = SystemProperties.getBoolean("ro.virtual_ab.compression.enabled") get() = SystemProperties.getBoolean("ro.virtual_ab.compression.enabled")
// 计算目录大小(递归)
private fun calculateDirectorySize(directory: File): Long {
var size = 0L
try {
if (directory.exists() && directory.isDirectory) {
directory.listFiles()?.forEach { file ->
size += if (file.isDirectory) {
calculateDirectorySize(file)
} else {
file.length()
}
}
}
} catch (e: Exception) {
// 可能因权限问题无法访问某些目录
}
return size
}
// 格式化存储大小
fun formatBytes(bytes: Long): String {
return when {
bytes < 1024 -> "$bytes B"
bytes < 1024 * 1024 -> String.format("%.2f KB", bytes / 1024.0)
bytes < 1024 * 1024 * 1024 -> String.format("%.2f MB", bytes / (1024.0 * 1024))
else -> String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024))
}
}
} }