存储信息修改
This commit is contained in:
parent
a43fcad558
commit
5239088041
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user