Skip to content

Instantly share code, notes, and snippets.

@li-jkwok
Created August 1, 2016 18:39
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save li-jkwok/e460a042326e8509ada9ec23ae677bdf to your computer and use it in GitHub Desktop.
Save li-jkwok/e460a042326e8509ada9ec23ae677bdf to your computer and use it in GitHub Desktop.
Getting Total Disk Space Available for Android Device
/**
* 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;
}
@m-asadullah
Copy link

As of API 18: Android 4.3 (Jelly Bean)

getBlockCount() is deprecated, so use getBlockCountLong() instead.
getBlockSize() is deprecated, so use getBlockSizeLong() instead.

@DigitalSolomon
Copy link

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.

@mddanishansari
Copy link

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
}

@m-asadullah
Copy link

@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?

@m-asadullah
Copy link

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
}

@mddanishansari
Copy link

@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)

@mddanishansari
Copy link

mddanishansari commented Jan 10, 2024

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 ;(

@m-asadullah
Copy link

@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 $1024^3$ bytes,
1 GB = 1024x1024x1024 bytes
while
1 GB in decimal is $1000^3$ bytes.
1 GB = 1000x1000x1000 bytes
This means that a 128 GB device in decimal is actually 119 GB in binary.

@mddanishansari
Copy link

@m-asadullah Thanks for the explanation

@leeyisoft
Copy link

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()
    }


}


@mohammednawas8
Copy link

mohammednawas8 commented Jan 22, 2024

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)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment