4

Recently, I needed to be able to write some data strictly on a phone's external, removable storage (aka SDCard). For lower-end devices without "external" internal storage (you know what I mean), this isn't an issue as

Environment.getExternalStorageDirectory().getAbsolutePath(),

which returns

/mnt/sdcard

is also the path to the sdcard. However on higher-end phones with built-in flash storage (sgs 2 for example), /mnt/sdcard, which is returned from Environment.getExternalStorageDirectory().getAbsolutePath(), is just the path to the internal storage. The real path to the sdcard is `

/mnt/sdcard/external_sd`.

This doesn't stop here, however, as when I tried with an sgs2 that is upgraded to ICS, the path to the sd card is now

/mnt/emmc.

Now I'm trying to build a general Utility class called ExternalStorage which has a static method that returns the path to the sdcard root (as well as some other methods to get the total space, available space, space consumed by a particular dir, etc.) So far, what I have is this:

Updated version:

public static String getRemovableStoragePath() {

        File f = null;
//      Log.d(TAG, "Build.DEVICE: " + Build.DEVICE);
//      Log.d(TAG, "Build.MANUFACTURER: " + Build.MANUFACTURER);
//      Log.d(TAG, "Build.MODEL: " + Build.MODEL);

        if (Build.VERSION.RELEASE.startsWith("4")) {
            f = new File("/mnt/emmc");
        }
        if (Build.MODEL.toLowerCase().startsWith("mele")) {
            return "/mnt/extern_sd0";
        }
        if (Build.DEVICE.equals("nuclear-zoop") || Build.DEVICE.equals("nuclear-f900")) {
            f = new File("/mnt/extsd");
        }

        String path = Environment.getExternalStorageDirectory().getAbsolutePath();
        String extendedPath = "";
        if (Build.DEVICE.toLowerCase().contains("samsung") || Build.MANUFACTURER.toLowerCase().contains("samsung")) {
            extendedPath = "/external_sd/";
            try {
                f = new File(path + extendedPath);
                if (f.exists() && f.isDirectory()) {
                    return f.getAbsolutePath();
                } else if (Build.MODEL.toLowerCase().contains("gt-i9300")) {
                    extendedPath = "/mnt/extSdCard/";
                    try {
                        f = new File(extendedPath);
                        if (f.exists() && f.isDirectory()) {
                            return f.getAbsolutePath();
                        }
                    } catch (Exception e) {
                        // continue execution
                    }
                } else {
                    extendedPath = "/sd";
                }
            } catch (Exception e) {
                // contine execution
            }
        } else if (Build.DEVICE.toLowerCase().contains("e0") || Build.MANUFACTURER.toLowerCase().contains("LGE")) {
            extendedPath = "/_ExternalSD/";
        } else if (Build.MANUFACTURER.toLowerCase().contains("motorola") || Build.DEVICE.toLowerCase().contains("olympus")) {
            f = new File("/mnt/sdcard-ext");
        }
        try {
            if (!extendedPath.equals("")) {
                f = new File(path + extendedPath);
            }
            if (f.exists() && f.isDirectory()) {
                //              Log.d(TAG, "path: " + f.getAbsolutePath());
                return f.getAbsolutePath();
            } else {
            }
        } catch (Exception e) {
            //          e.printStackTrace();
            // f is probably null. no need to print stacktrace.
            return path;
        }

        return path;
//      return Environment.getExternalStorageDirectory().getAbsolutePath();
    }

Has anyone done this already? I know I'm missing many mfg-specific paths, so I need help in completing this utility to support as many android phones as possible.

josephus
  • 8,284
  • 1
  • 37
  • 57
  • 1
    I can suggest a somewhat different approach: How about checking the system's mounted filesystems table and discovering the path from there? As the external storage will be the last mounted filesystem, it "should" be the last entry in the table. You can get the table by looking at /proc/mounts file. However, this is not a "standard" method as it expects that the underlying file system is somewhat exposed to the programmer. However, it'll be lesser code. If you want I can create an answer to your question with more details than this. – Samveen May 17 '12 at 04:34
  • does that hold true for phones that you can usb-connect to mount both internal and sd card memory? – josephus May 17 '12 at 06:01
  • The /proc/ path on the phone is the information interface of the underlying linux kernel running on the phone. As /proc/mounts is the mounted file systems information of the kernel, the path will be there no matter what/where you access it from(via the underlying OS's FS interfaces or Android's Java based interfaces). However, I cannot confirm if it is world readable on all phones. You'll have to test that out yourself. As for your question about usb-connect, would you clarify that a little more? – Samveen May 17 '12 at 06:27
  • did you get the solution for the same? – Rajnikant Jul 18 '12 at 11:21
  • @Samveen can you provide me with code to get the table of mounted filesystem since iam not familiar to linux, thanks – AnasBakez Jul 25 '12 at 11:28

1 Answers1

2

I'm not sure how reliable this would be but since the removable SD card contains the LOST.DIR folder at its root and gets recreated upon boot (in cases where the user might delete it)...

    File root = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
    for (File sub : root.listFiles()) {
        if (new File(sub + "/lost.dir").exists()) {
            // 'sub' is probably the removable SD
            break;
        }
    }    

If 'sub' is found with a LOST.DIR folder , might want to write its value to sharedPrefs so that this lookup is only performed one time (if there is no value stored) and then just fetched from prefs, OR so that the app knows this path even in case the user deleted LOST.DIR and it currently doesn't exist anywhere.

mjp66
  • 4,214
  • 6
  • 26
  • 31
  • nice observation. though this will only work after the user reboots from a formatted memory card. also, as per my experience with some Samsung 2.3.x devices with internal memory, the path exists, and i can even write on it, when i remove the sd card. – josephus May 29 '12 at 02:11