Android devices with Environment.getExternalStorageDirectory() != /mnt/sdcard/? - android

Of course in my code I use Environment.getExternalStorageDirectory() instead of hardwiring /mnt/sdcard/. But I just realized that when I export data from my application via a database dump in an exchange format, file paths are /mnt/sdcard/... This may explain some strange errors that I have seen in the logs from users.
I will make the appropriate changes in the import modules. But I am curious - does any Android devices > 1.6 have Environment.getExternalStorageDirectory() != /mnt/sdcard/ ?

Actually, some for some devices the getExternalStorageDirectory() will return localization for internal memory (internal SD card). The removable SD card is located as mount point below, usually getExternalStorageDirectory()+"/sd" or getExternalStorageDirectory()+"/external_sd". Unfortunately, there is no standard for this and you won't know what kind of storage you are pointing at.

No. I haven't seen any devices with sdcard mounted to different location. And I've played with more then 10 different devices from most popular vendors.
Having said that, you shouldn't rely on this fact. Especially if you have such an easy way to get path to External storage.

I had a user of one of my apps report this, he was using Andy 2.2 IIRC but I can't remember what device he was using. The path can be found using
Environment.getExternalStorageDirectory().getPath()
I think the path my user got was /sdcard & not /mnt/sdcard like my HTC phone does.

Related

how to save files on externalStorage

I've already figured out that on some devices the externalStorage may be set as the device Storage, like on my Samsung Galaxy 4 10.1 with 5.0.2. Android OS.
The Question now is how can I still say to save it on the SD-Card ?
For Example:
private File makeFolder(String folder) {
File dir = new File(Environment.getExternalStorageDirectory() + "/" + folder + "/");
if (!(dir.exists() && dir.isDirectory())) {
dir.mkdirs();
}
return dir;
}
On my older Devices (like my Sony Ericson Pro) this works just fine. So how to solve this?
You are into a slightly complicated area of Android programming :)
I can not give you complete answer here, but I can give some pointers:
On almost all devices I've seen, Environment.getExternalStorageDirectory() will give you the path to the root directory of an emulated SDCARD - which is not a physical SDCARD. Manufacturers are free to map the physical SDCARD to this path - but usually, they emulate an SDCARD using internal memory)
And prior to Kitkat, there are no API available to even to determine the presence of a physical SDCARD.
From Kitkat onwards, you can see if a physical SDCARD is present by checking the result of appContext.getExternalFilesDirs() which will give you your app's private data directory path on all available storage media.
If a physical SDCARD is present and mounted, appContext.getExternalFilesDirs() will give you two paths are result. Then the first one is for the emulated SDCARD. You may notice that this path will contain same subpath that returned by Environment.getExternalStorageDirectory().
The following example will make this clearer. I am assuming a Samsung S4 with a real SDCARD inserted and mounted in it
The first path returned will be:
/storage/emulated/0/Android/data/com.example.yourapp/files.
The second path is interesting - as this path is your app's accessible area on the the real physical SDCARD. This path will be of the form:
/storage/extSdCard/Android/data/com.example.yourapp/files
This is the only path that you have write access in Kitkat.
So, from Kitkat onwards, from the presence of these two paths, (and added checks for mounted SDCARD), you can easily find out whether your app is running on a phone with real SDCARD or not. You can even parse the second path to get the root directory of the real SDCARD (just remove /Android/... substring from this path)
And yes, now you know why you are so restricted with real SDCARDs in Kitkat. As said in italics above, you have write access to only that directory on a physical SDCARd in Kitkat.
Now comes Marshmallow and things changes again. In Marshmallow you have a storage framework, using which you can present the user with a permission dialog box and you can tell him to grant your app complete access to whatever device or directory therein. Please search for "Intent.ACTION_OPEN_DOCUMENT_TREE" for nice tutorials.
So, in short, as of now, there is no nice way in Android to deal with SDCARD which works uniformly in all versions. Before Kitkat, it is a grey area, In Kitkat, you are severely restricted, and in Lollipop, you are stuck with a system Activity with an absurd looking GUI for permission and not so easy to use framework.

When does getExternalStorageDirectory().getPath() return something else than "/sdcard/"?

I get a warning from android lint:
Do not hardcode "/sdcard/"; use Environment.getExternalStorageDirectory().getPath() instead
I will fix this, but still would need to know:
On which (example) devices is this a problem, what other (example) paths can you get from this call? If this is not related to specific devices, to what is it specific or when would it happen?
Under what circumstances is there no /sdcard/ directory that my app could write to?
The app has the rights
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
what other (example) paths can you get from this call?
Partly, it is whatever the manufacturer wants.
Partly, it will vary based on the user account that is running your app. Please bear in mind that for a few years (since the release of Android 4.2), Android devices can have multiple user accounts (tablets starting with 4.2, phones starting with 5.0). Each user gets a distinct location for internal and external storage, and there is no guarantee as to what actual filesystem paths those will point to.
NEVER HARDCODE ROOT PATHS to internal or external storage. Always use an appropriate method for getting a root location, then use the appropriate File constructor to point to whatever you want within there.
The app has the rights
Since there is no WRITE_INTERNAL_STORAGE permission in Android, please remove it.
The SD card path is different for different Android manufacturers. So I make my own research with my friends' sdcard on their phone. And the result:
Sony XPERIA X10i (my phone)
Android 2.3.3 (Gingerbread)
path for phone internal memory: not available
path for sdcard: /mnt/sdcard/
Samsung Galaxy S3 Mini & Samsung Galaxy Young (given same result)
Android 4.2.2 (JellyBean)
path for phone internal memory: /storage/sdcard0/
path for sdcard: /storage/extSdCard/
OPPO (I don't remember what her phone type is)
Android 4.2.2 (JellyBean)
path for phone internal memory: /storage/sdcard0/external_sd/
path for sdcard: /sdcard0/
I wrote the result in a book. So my suggestion, never use hardcode for sdcard's path. Check here to know your sdcard's path.
The external storage may point other places,
you may define and mount other place as device external storage,
it a configure option, that why you have a Lint warning.
For example if the device support External SD card, than the external sdcard (getExteranlStorage()) will point to him (the exteranl sdcard will mount at /nmt/sdcard#/), top keep the internal sdcard free.
To make it clear
The /sdcard/ == /mnt/sdcard[0] -> internal sdcard
other sdcard will mount at /mnt/sdcard[1..]/ -> external sdcard
And also the manufacture of the device can call it as he wish (/sdcard/ is just a convention not a must have)

Comparing sdcard paths

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.

Android External Storage among mobile brands

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.

Programmatically accessing internal storage (not SD card) on Verizon HTC Droid Incredible (Android)

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)

Categories

Resources