42

As of API level 8, it seems Android has redefined what "external" storage is. Reading through http://developer.android.com/reference/android/os/Environment.html, attached to the documentation for getExternalStorageDirectory I see the comment: "don't be confused by the word 'external' here. This directory can better be thought as media/shared storage... In devices with multiple 'external' storage directories... , this directory represents the 'primary' external storage that the user will interact with."

My app writes files to the path obtained by getExternalStorageDirectory, and I've had users ask for an option to write to their removable SD card instead. I had always assumed that getExternalStorageDirectory returned the path to the removable SD card, but this is no longer true. How do I access the path to this SD card?

skyler
  • 8,010
  • 15
  • 46
  • 69

3 Answers3

34

According to the source, getExternalStorageDirectory is implemented to return whatever is set as "external storage" in the device environment:

public static File getExternalStorageDirectory() {
    return EXTERNAL_STORAGE_DIRECTORY;
}

and EXTERNAL_STORAGE_DIRECTORY is:

private static final File EXTERNAL_STORAGE_DIRECTORY
        = getDirectory("EXTERNAL_STORAGE", "/sdcard");

static File getDirectory(String variableName, String defaultPath) {
    String path = System.getenv(variableName);
    return path == null ? new File(defaultPath) : new File(path);
}

In contrast, getExternalStoragePublicDirectory(String type) requires one of these strings:

DIRECTORY_MUSIC, DIRECTORY_PODCASTS, DIRECTORY_RINGTONES, DIRECTORY_ALARMS, DIRECTORY_NOTIFICATIONS, DIRECTORY_PICTURES, DIRECTORY_MOVIES, DIRECTORY_DOWNLOADS, or DIRECTORY_DCIM. May not be null.

so it is not meant to return the sd-card root.

An alternative:

Finally, getExternalStorageState() will return the filesystem mounted in /mnt/sdcard/. According to CommonsWare in this answer: Find an external SD card location, there is no way to directly get the external sdcard (if it even exist).

An alternative would be to check isExternalStorageRemovable () and give a manual option if it is false.

Community
  • 1
  • 1
Aleadam
  • 40,203
  • 9
  • 86
  • 108
  • BTW: I did not see your edit removing the `getExternalStoragePublicDirectory` part of the question until now. – Aleadam May 18 '11 at 18:43
  • 2
    Sorry about that—I removed it and provided an edit message explaining that I had removed it, but I guess edit messages aren't shown? Since there's no way to get the location of the removable SD card, if it exists, what is the purpose of this SD card slot in phones like the Atrix? Is it just for storing data while mounted to a computer, like a thumb drive? – skyler May 18 '11 at 19:32
  • @skyler that's OK, I just did not want my answer to seem out of context. Honestly, it is a much better option the internal sd. It's faster, more reliable and you know it's always there. But if they ask for it, give a manual option as I said above (a Save As dialog). For example, in my captivate, the internal is `/sdcard` and the external is `/sdcard/external_sd/` – Aleadam May 18 '11 at 19:38
  • 1
    I can't believe there is now no common SDcard mount point...ugh so now the sdcard mount point is arbitrary depending on phone type? – JPM Apr 27 '12 at 18:58
  • @Aleadam But can we guarantee that external sdcard is one of subdirectories of getExternalStorage() path ?? and any way to tell android to run media scanner on it ?? – Ahmed Jan 27 '13 at 23:11
  • 3
    this answer does not really answer anything – Caner Sep 17 '13 at 12:53
  • 8
    I agree with @Caner. This answer doesn't answer the question: How do we find the removable storage location. I've been looking everywhere, but when I test on Samsung devices every device returns the internal storage location. How do I locate the path to the *removable* SD Card? – b.lyte Sep 05 '14 at 23:15
  • still not working for me, my sdcard location is /storage/sdcard1/ but the above method is returning me /storage/emulated/legacy, which is the path for internal storage, not the sdcard – Narendra Singh Sep 12 '16 at 12:31
  • @clu You can access it by using `new File("/mnt/sdcard/")`. This returns a reference to the removable mounted SD Card directory. Yes, I know it's hard-coded, but "/mnt" is a default Linux directory, so there is little chance of variation. – Chris - Jr Feb 13 '18 at 08:09
  • `getExternalStoragePublicDirectory(String type)` can also accept "DIRECTORY_DOCUMENTS" as of API 19, according to [https://developer.android.com/reference/android/os/Environment.html#getExternalStoragePublicDirectory(java.lang.String)] – Benjamin Kershner May 10 '18 at 17:44
3

For API 17 I get the following returns:

Environment.getExternalStoragePublicDirectory(Environment.MEDIA_MOUNTED) 
returns:-------> /storage/sdcard0/mounted

Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
returns:-------> /storage/sdcard0/DCIM

Environment.getExternalStoragePublicDirectory(Environment.MEDIA_SHARED) 
returns:-------> /storage/sdcard0/shared

Environment.MEDIA_MOUNTED 
returns:-------> mounted

Environment.getExternalStorageDirectory()
returned:-------> /storage/sdcard0

All return location of internal phone memory.

Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
1

To be sure you are accessing the sd card you can use:

System.getenv("SECONDARY_STORAGE")

however - please keep in mind that even if you set all the correct permissions in the manifest - The only place 3rd party apps are allowed to write on your external card are "their own directories" (i.e. /sdcard/Android/data/)

Try to write to anywhere else and you will get exception: EACCES (Permission denied)

Elad
  • 1,523
  • 13
  • 10
  • and after all the above Environment.getExternalStorageDirectory() has been deprecated in API 29. Google seems to continuously mess around with sdcards and permissions. I have remarked before that imho they want to get rid of the external sdcard but cant – Theo Aug 08 '19 at 14:18