-
-
Save li-jkwok/e460a042326e8509ada9ec23ae677bdf to your computer and use it in GitHub Desktop.
/** | |
* Get the total disk space available on this Android Device | |
* | |
* @return total size (in bytes) that is the total disk space avaialble on the device. | |
*/ | |
public static long getTotalDiskSpace() { | |
StatFs statFs = new StatFs(Environment.getRootDirectory().getAbsolutePath()); | |
long totalDiskSpace = statFs.getBlockCount() * statFs.getBlockSize(); | |
return totalDiskSpace; | |
} |
Per the Android documentation, Environment.getRootDirectory()
returns root of the "system" partition holding the core Android OS. This is read-only and apps don't write here, so depending on your definition of "available disk space", this might not be what you're looking for.
Environment.getDataDirectory()
might be closer to what you're looking for, as that returns the directory of the internal storage on the device.
getStorageDirectory()
returns the directory for external (SDCard) based storage directories.
Any update on this on how to use in Android 14? Because it is giving wrong data in Android 14.
For eg. Total storage of my Emulator is 8GB (as I saw in Settings app) but the Environment.getRootDirectory()
is giving 0.79GB, Environment.getDataDirectory()
and Environment.getExternalStorageDirectory()
are giving 5.8GB. My app also has android.permission.MANAGE_EXTERNAL_STORAGE
permission
This is my code
/**
* Return storage in GB
*/
fun getTotalStorage(): Double {
val statFs = StatFs(Environment.getRootDirectory().absolutePath) // also tried Environment.getDataDirectory() and Environment.getExternalStorageDirectory()
val blockCount = statFs.blockCountLong.toDouble()
val blockSize = statFs.blockSizeLong.toDouble()
return (blockCount * blockSize) / 1024.0 / 1024.0 / 1024.0
}
@mddanishansari, if emulator is 8GB(total storage), then how much storage is available(free) right now?
Go to Google Play Store app check there, or install another device information app to check this?
What is your minimum API of app?
If your app minAPI is 26, then try this
fun getTotalStorage(): Double {
val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager
val storageStatsManager = getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
val storageVolumes = storageManager.storageVolumes
var totalBytes = 0L
for (volume in storageVolumes) {
val uuid = volume.uuid?.let { UUID.fromString(it) } ?: StorageManager.UUID_DEFAULT
totalBytes += storageStatsManager.getTotalBytes(uuid)
}
return totalBytes.toDouble() / 1024.0 / 1024.0 / 1024.0
}
@m-asadullah It is afresh emulator with 8.0 GB total storage and 2.7 GB is used (system + default apps + my app {hardly some KB}), so I'm assuming 5.3 GB is free.
I tried your code and it is crashing on emulator with this exception java.lang.IllegalArgumentException: Invalid UUID string 1320-0E07
so I tried on my phone(also running Android 14) which has 128 GB total storage and it is showing 119.29 GB
Also this is interesting comment I found on another Flutter package Github repo mboeddeker/disk_space#6 (comment) which you might want to read. (Even though that's Flutter package but in the lower level it must be using some Android native API)
Ok so I modified your code a bit and instead of using for loop, I used first volume like this val volume = storageVolumes.first()
and now it is giving correct bytes, 128000000000 bytes for 128 GB phone but when I convert it to GB with this formula GB = Bytes / 1024 / 1024 / 1024
it is giving 119.29 GB. Apparently the correct formula would be divide the result consecutively 3 times with 1000.0 which gives correct result but I think that's not the right way, correct? I'm so confused ;(
@mddanishansari, it depend of formatting of storage.
The base unit of measurement, which can be either binary (base 2) or decimal (base 10). Binary units are used by computers and operating systems, while decimal units are used by manufacturers and marketers.
For example,
1 GB in binary is
1 GB = 1024x1024x1024 bytes
while
1 GB in decimal is
1 GB = 1000x1000x1000 bytes
This means that a 128 GB device in decimal is actually 119 GB in binary.
@m-asadullah Thanks for the explanation
If your app minAPI is 26, then try this
fun getTotalStorage(): Double { val storageManager = getSystemService(Context.STORAGE_SERVICE) as StorageManager val storageStatsManager = getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager val storageVolumes = storageManager.storageVolumes var totalBytes = 0L for (volume in storageVolumes) { val uuid = volume.uuid?.let { UUID.fromString(it) } ?: StorageManager.UUID_DEFAULT totalBytes += storageStatsManager.getTotalBytes(uuid) } return totalBytes.toDouble() / 1024.0 / 1024.0 / 1024.0 }
package com.icstoragespace.ic_storage_space
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
import android.os.Environment
import android.os.StatFs
import android.content.Context
import android.os.storage.StorageManager
import android.app.usage.StorageStats
import android.app.usage.StorageStatsManager
import java.io.IOException
import java.util.UUID
/** IcStorageSpacePlugin */
class IcStorageSpacePlugin : FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel: MethodChannel
lateinit var context: Context
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
context = flutterPluginBinding.getApplicationContext()
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "ic_storage_space")
channel.setMethodCallHandler(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
"getFreeDiskSpaceInBytes" -> result.success(getFreeDiskSpaceInBytes())
"getTotalDiskSpaceInBytes" -> result.success( getTotalDiskSpaceInBytes())
else -> result.notImplemented()
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
// context = binding.getApplicationContext();
channel.setMethodCallHandler(null)
}
private fun getFreeDiskSpaceInBytes(): Long {
val stat = StatFs(Environment.getExternalStorageDirectory().path)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
return stat.blockSizeLong * stat.availableBlocksLong
else
return stat.blockSize.toLong() * stat.availableBlocks.toLong()
}
private fun getTotalDiskSpaceInBytes(): Long {
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager;
val storageStatsManager = context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager;
val storageVolumes = storageManager.storageVolumes;
var totalBytes = 0L;
for (volume in storageVolumes) {
val uuid = volume.uuid?.let { UUID.fromString(it) } ?: StorageManager.UUID_DEFAULT;
totalBytes += storageStatsManager.getTotalBytes(uuid);
}
return totalBytes.toLong();
}
private fun getTotalDiskSpaceInBytes_(): Long {
val stat = StatFs(Environment.getRootDirectory().absolutePath)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
return stat.blockSizeLong * stat.blockCountLong
else
return stat.blockSize.toLong() * stat.blockCount.toLong()
}
}
This code worked for me, but im still looking for an implementation that works on old versions
fun getTotalStorageSize(context: Context): Double {
val storageManager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
val storageStatsManager = context.getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager
val uuid = storageManager.getUuidForPath(Environment.getDataDirectory())
val totalBytes = storageStatsManager.getTotalBytes(uuid)
val sizeRepresentation = StorageUtil.getStorageSizeRepresentation(totalBytes)
val base = sizeRepresentation.base.toDouble()
val totalGB = totalBytes / (base * base * base)
totalGB
} catch (e: IOException){
0.0
}
} else {
TODO("Implementation for devices that work on lower versions")
}
}
object StorageUtil {
/**
* Determines if the data size is in Binary or in Decimal.
*/
fun getStorageSizeRepresentation(storageSizeInBytes: Long): SizeRepresentation {
/**
* In Binary representation the base is 2 and the storage size could be 2, 4, 8, 16, 32, 64, 128, ...
* In Decimal representation we multiply by 10
* To determine what type of representation the device uses we can convert the total storage size in bytes to Binary by dividing it on 1024 three times
* Then we take Log(binary_size) of base 2, if the reminder = 0 then we know we have Binary representation.
*/
return if (log(storageSizeInBytes / (1024.0.pow(3)), 2.0) % 1.0 == 0.0) {
SizeRepresentation.Binary
} else {
SizeRepresentation.Decimal
}
}
}
enum class SizeRepresentation(val base: Int) {
Binary(1024), Decimal(1000)
}
As of API 18: Android 4.3 (Jelly Bean)
getBlockCount() is deprecated, so use getBlockCountLong() instead.
getBlockSize() is deprecated, so use getBlockSizeLong() instead.