Tuesday, August 9, 2011

Check external SD card on Android device

Want to check if external (I mean the one which can be freely removed from the device without removing the battery) SD card is inserted on the device? The standard Android API has only one method to call for it:

Environment.getExternalStorageDirectory()

Sad, but this one returns only directory, which is mounted on the device as "external" (usually, "/mnt/sdcard/"), but not the actual removable media. You can hard-code the real external storage directory, which can differ on different devices. For instance, Samsung's Galaxy family devices state the external SD drive to be mounted on

/mnt/sdcard/external_sd/

Anyway, before trying to get actual external path you should consult to the device manufacturer, for what mount path you should be looking for. And still, even when you know external path, you can be fucked up trying to look that folder directly.

Consider we have a Galasy S which has external SD card path as of "/mnt/sdcard/external_sd". The most obvious way to check it is to create a File object and look for its isExists() boolean:

File f = new File("/mnt/sdcard/external_sd");
if (f.isExists()) {
    // Dance
}



But your program can screw things up if no SD card is really mounted onto this directory. It's Linux, they can have external drive been mounted as your finger! So don't trust that file's isExists() flag - it can return true when "external_sd" is exists, but no physical external SD card is mounted onto it.

So, you fought to death with phone manufacturer to get that "external path" value just to realize that it's useless anyway? No, my little sorcerer, there is always a bit of saving magic for every "impossible" task.

We're still on Linux' territory, remember? I mean, yeah, we are on Android, but still on Linux. It's some kind of Two-Face.



Well,  let's use this for our advantages. On Android device, we can get system file, which contains all currently mounted folders and path, and check, if our "external" path has actually been mounted with real media.


try {
    // Open the file
    FileInputStream fs = new FileInputStream("/proc/mounts");

    DataInputStream in = new DataInputStream(fs);
    BufferedReader br = new BufferedReader(new InputStreamReader(in));

    String strLine;
    StringBuilder sb = new StringBuilder();

    //Read File Line By Line
    while ((strLine = br.readLine()) != null)   {
        // Remember each line
        sb.add(strLine);
    }

    //Close the stream
    in.close();
} catch (Exception e) {
    //Catch exception if any
    e.printStackTrace();
}


So, we read "/proc/mounts" file line by line, adding each one to the StringBuilder class instance. After all, if there nothing screwed up, we'll have file contents in memory, and can therefore cast any "contains-like" spell'

if (sb.contains("mnt/sdcard/external_sd")) {
    // Dance
}


Sweet coding.