When thinking about this question I asked, I wondered: Is there really no way of finding out if a adopted SD is present?
With a Motorola G3 there were two paths returned by getExternalFilesDirs() when an external SD was present, but only one (the emulated one, thats always present) when formatting the SD as internal. Other devices seem to behave similar.
So, if I am looking to know if there is a internal SD present, where would I need to look? Is there anything (non manufacturer specific) provided, so e.g. I could check, if the user expects to use the internal emulated Environment.getExternalStorageDirectory() because he has mounted a internal SD?
Related
I've been looking for a way to get the SD card directory for a majority of the day. I've recently found out that the function call getExternalStorageDirectory under some circumstances returns a path that is on-board memory. I am supporting API 19 and above.
The common answer stackOverflow gives to get the SD card path is
Environment.getExternalStorageDirectory().getAbsolutePath();
which is not working for my devices because the external storage returned is non-removable memory (Samsung Tab S2).
I've been able to use getExternalFilesDirs to return the list of directories, and in my testing it will return two directories, the on-board memory location for the application and the SD card that I've mounted. However the function call
isExternalStorageRemovable was not introduced until API 21. This was the clearest candidate that I could find that would have satisfied what I am trying to do, which is make sure that I am actually writing to the external SD Card.
1) Is there a way to verify if the directory returned by getExternalFilesDirs is removable or external in API 19?
2) Can it be assumed that if the only storage use cases are "Internal Memory" and "Internal Memory and SD Card" that the SD card location will always be returned second from getExternalFilesDirs as has happened in my brief testing?
I've recently found out that the function call getExternalStorageDirectory under some circumstances returns a path that is on-board memory
External storage is not removable storage. On the vast majority of Android devices, getExternalStorageDirectory() returns a location that is part of the on-board flash. That has been the case for ~7 years, since the introduction of Android 3.0.
Is there a way to verify if the directory returned by getExternalFilesDirs is removable or external in API 19?
If getExternalFilesDirs() returns 2+ items, the second and subsequent ones are on removable storage.
Can it be assumed that if the only storage use cases are "Internal Memory" and "Internal Memory and SD Card"
That is not a safe assumption.
that the SD card location will always be returned second from getExternalFilesDirs as has happened in my brief testing?
The first entry returned by getExternalFilesDirs() is the same as what is returned by getExternalFilesDir() (the older, singular form). While the vast majority of Android devices have fixed external storage, there may be some devices where external storage is actually removable. In this case, the Android SDK and framework still consider this to be external storage — after all, that is what the device manufacturer told the firmware to do. And, in this case, the location returned first from getExternalFilesDirs() would be physically removable, even if it is not what Android developers typically think of as removable storage. This is a fringe scenario; I cannot name any current device models that have external storage implemented on a removable card.
Also, bear in mind that not all removable storage is in the form of a card. USB OTG thumb drives are also removable storage, as are more traditional thumb drives for those devices that have a USB Type A port (e.g., Android TV, Samsung Galaxy S8 in a DeX dock).
which is make sure that I am actually writing to the external SD Card.
I strongly recommend that you stop thinking in terms of media. Use things like the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT, ACTION_CREATE_DOCUMENT) to allow the user to choose places to store content from all possibilities at their disposal: external storage, removable storage, Google drive, Windows file servers, etc.
Device 1
/sdcard attached to real sd card
/mnt/sdcard attached to real sd card
Device 2
/sdcard attached to internal memory
/mnt/sdcard attached to internal memory
/external_storage(something like this) to real sd card
.
.
/sdcard and /mnt/sdcard seems to have the same location. Always ?
My question is, how do I know if they attached to same directory ?
I tried new File(path1).equals(new File(path2)); but it return false. Only way I see is, create a hidden file with unique id and check the existence in both paths.
PS : I'm aware of Environment.getExternalStorageDirectory(). But I need these paths for some specific purpose.
/sdcard and /mnt/sdcard are not always the same. There are many paths that can exsist such as:
/emmc
/mnt/sdcard/external_sd
/mnt/external_sd
/sdcard/sd
/mnt/sdcard/bpemmctest
/mnt/sdcard/_ExternalSD
/mnt/sdcard-ext
/mnt/Removable/MicroSD
/Removable/MicroSD
/mnt/external1
/mnt/extSdCard
/mnt/extsd
/mnt/usb_storage <-- usb flash mount
/mnt/extSdCard <-- usb flash mount
/mnt/UsbDriveA <-- usb flash mount
/mnt/UsbDriveB <-- usb flash mount
There should be no reason that you would need a direct path hard coded to the internal or external memory when they make functions available for that. Anything that you are hard coding will be the same as what you get back from the functions that you have listed only the will be for that specific devices.
This will give you a string of the absolute path to a file on the external storage:
String myPath = sdcardEnvironment.getExternalStorageDirectory().getAbsolutePath() + "/folder file is in/file you want path to";
And this will get you the path your applications internal storage:
this.getApplicationContext().getFilesDir()
You cannot always access the external SD card from code because of the way that newer versions of android partition itself. Here is statement directly from android dev site:
It's possible that a device using a partition of the internal storage for the external storage may also offer an SD card slot. In this case, the SD card is not part of the external storage and your app cannot access it
new File("/sdcard").getCanonicalPath().equals(new File("/mnt/sdcard").getCanonicalPath())
Omitted are exception handling and other niceties. Note, however, that ObieMD5 is correct, and you should not be doing this, as you can see from the list of paths in the answer above.
Also note that this method will only resolve symlinks; if your device uses mount instead to have the same space accessible from two locations, this method will not work.
attached to real sd card
The Android SDK, at present, has no concept of "real sd card". There is external storage. The definition of where external storage resides is up to the device manufacturer.
attached to internal memory
Those paths at best refer to external storage, and at worst do not exist.
/sdcard and /mnt/sdcard seems to have the same location. Always ?
No. Those paths may not even exist on some devices, as there is no requirement that they exist, and modern devices do not use those paths. Always use methods on Environment or Context to find locations on external storage.
I am facing interesting problem. I have discovered, that Samsung in it's own Android phones has two implementations of storage.
1st: /sdcard - is internal memory and /sdcard/external_sd is actually inserted memory card
2nd: /storage/sdcard0 - is internal memory and /storage/ExtSdCard is actually inserted memory card.
My app needs data to be stored in sd card, so I am facing problem, how to determine, which folder might be sd card link or not. Do you know situation of any other Android maker (LG, HTC, Sony), how to cope with external SD cards and how they are visible in android system?
It is really so simple. When you consider your samsung mobiles it is the internal storage that acts as your sdcard.
if you are looking for to save a file in Sdcard, you have to stop hard coding the path like,
/mnt/sdcard.. and so.
instead use, Environment.getExternalStorageDirectory();
This will return the path to your sdcard straight away.
And from there, add Environment.getExternalStorageDirectory()+File.separator+"your directoryname";
And this works for all brands not unique to Samsung.
I tried to figure out the the right external storage (additional sdcard with more space ) location of an Android device.
I know from different user, that the location is not always the same.
The method Environment.getExternalStorageDirectory returns me always mnt/sdcard.
I have the following variants are reported from users:
mnt/sdcard/tflash
mnt/sdcard/external_sd
mnt/sdcard
How can I determine the real location of an external sd-card?
Environment.getExternalStorageState() returns path to internal SD mount point like "/mnt/sdcard"
No, Environment.getExternalStorageDirectory() refers to whatever the device manufacturer considered to be "external storage". On some devices, this is removable media, like an SD card. On some devices, this is a portion of on-device flash. Here, "external storage" means "the stuff accessible via USB Mass Storage mode when mounted on a host machine", at least for Android 2.x and above.
But the question is about external SD. How to get a path like "/mnt/sdcard/external_sd" (it may differ from device to device)?
Android has no concept of "external SD", aside from external storage, as described above.
If a device manufacturer has elected to have external storage be on-board flash and also has an SD card, you will need to contact that manufacturer to determine whether or not you can use the SD card (not guaranteed) and what the rules are for using it, such as what path to use for it.
How can I determine the real location of an external sd-card?
=> Environment.getExternalStorageDirectory() gives you the exact location of your external storage device. Path may be different because it depends on the consideration of manufacturer.
For example: I found /sdcard on some HTC devices and /mnt/sdcard on some samsung devices.
So Environment.getExternalStorageDirectory() is the correct way.
I'm trying to find information on how to programmatically access the HTC Droid Incredible's supposed 8GB of Internal Storage Memory.
To determine the External Storage (SD Card) Location, I'm using the command:
android.os.Environment.getExternalStorageDirectory().
I've not been able to find any corollary for Internal phone Storage.
In examining HTC/Google Nexus One, Motorola Droid, and HTC Dream/G1 phones, there (as would be expected) does not appear to be any Mount Point for such Arbitrary Internal Storage.
On these phones the Internal Storage is divided amongst /data, /system, and /cache partitions.
The Incredible's Internal Storage is certainly not going to be located in /system. /cache is also unlikely given that it is globally non-readable/non-executable.
I'd read in reviews that the phone will still be limited to 512MB or so for apps, suggesting that it is not simply a subdirectory of /data.
I do not have access to a Droid Incredible unit myself, of course.
There is more information here: Droid Incredible storage mount points. It seems that Droid Incredible mounts its internal storage to /emmc, supposedly mounted r/w. It is not yet verified whether the WRITE_EXTERNAL_STORAGE permission is necessary in order to gain r/w access - I'm trying to get this information from Google Code
I will probably solve this by allowing the user two options to store the data:
SD-Card
Droid Incredible-only Internal storage
Edit: It seems that the WRITE_EXTERNAL_STORAGE permission is sufficient: according to droidForums both /sdcard and /emmc has the same GID of 1015.
Edit2: According to Google Group Thread the Incredible returns /sdcard as the result value of Environment.getExternalStorageDirectory(). Therefore, the user needs to decide whether he wants to use /sdcard or /emmc. The auto-detection of Incredible may be based on existence of the /emmc path.
As you're aware access to internal storage is usually limited to certain directories for each application by permissions. This is to stop one application reading data from another and from accessing system files without using the APIs. This makes sense since, for example, if you had an internet banking application you wouldn't want other apps to be able to access any of its cached data.
Each application gets to store data in a directory under /data/data. However, normally you don't specify the paths explicitly but used methods like Context.openFileOutput() which creates the file in the appropriate subdirectory of your application's directly.
I agree with you that it is unlikely that the majority of the 8GB of the Incredible's storage will be used for the /data partition.
So if they are going to have a separate partition to allow music and photos to be stored easily on the phone's internal storage then they will have to do it in a way that's compatible with existing applications. This means using Environment.getExternalStorageDirectory() but since the Incredible also supports SD cards then you're right in that it's not obvious how this might work.
There is a thread on the Android Developers Google Group discussing this exact question. Whilst there isn't an answer (at the time of writing) for how the Incredible works there's a post which says the Samsung Galaxy solves the same problem in this way:
The internal storage is mounted at /sdcard
If an SD card is also available this can be found at /sdcard/sd
This seems a sensible solution since it will be compatible with existing applications, including those which have mistakenly hard coded /sdcard instead of using Environment.getExternalStorageDirectory().
So my advice would be to use Environment.getExternalStorageDirectory() when you're looking for large areas for storage - either SD card or internal to the phone - and hope that each phone returns something sensible.
Just simply use this:
String primary_sd = System.getenv("EXTERNAL_STORAGE");
if(primary_sd != null)
Log.i("EXTERNAL_STORAGE", primary_sd);
String secondary_sd = System.getenv("SECONDARY_STORAGE");
if(secondary_sd != null)
Log.i("SECONDARY_STORAGE", secondary_sd)