Ok, I have searched the forums high and low, and am unable to find an acceptable answer to test if the SD card is properly mounted and is writable on Android 7 devices. (There are many answers, but none that actually work).
I understand that one must use Environment.getExternalStorageState(), as per my code below:
pathName=context.getFilesDir().getAbsolutePath()+"/"+SavePath;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
pathName= Objects.requireNonNull(context.getExternalFilesDir(SavePath)).getAbsolutePath();
BUT...
Regardless whether the SD card is mounted or not, this always return TRUE, simply because the SD card is mounted as an emulated resource, NOT a removable resource.
I can use Environment.isExternalStorageEmulated() to check this state, BUT it still doesn't tell me whether the SD card is available or not. (i.e.: isExternalStorageEmulated() will always return true, whether there exists an SD card or not, because it is set by the file system on startup and doesn't seem to care whether there is a physical SD card in the slot or not).
Other than trying to write to the SD card, and capturing the exception error if it doesn't exist, is there any way to tell if an SD card is present or not BEFORE I attempt to write to it?
EDIT:
After reviewing the proposed solutions, this is the best I can come up with. This seems very clunky. Any ideas on how to improve this?
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
if (Environment.isExternalStorageEmulated()){
File[] storage=getExternalFilesDirs(null);
// Find the first non-emulated storage space
for (File file: storage){
if (!file.toString().contains("emulated/"))
System.out.println(file.toString());
}
}
}
Your edit answer looks good since you discard the emulated storage. As an alternative you can also count the directories. If it's greater than 1 (also discarding the emulated storage) then the storage has an SD card:
public boolean hasExternalSD() {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//External Storage Emulated
if (Environment.isExternalStorageEmulated()){
if (ContextCompat.getExternalFilesDirs(context, null).length > 1) {
return true;
}
}
}
return false;
}
Both getFilesDir() and getExternalStorageDirectory() are always available on every Android device.
They have nothing to do with a removable micro SD card.
Related
I'm developing with Android Studio on various emulated devices.
Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
always returned false UNTIL I chose to emulate SD cards on the emulated devices.
But the documentation at http://developer.android.com/training/basics/data-storage/files.html specifically states that
"there are always two storage spaces and the API behavior is the same whether the external storage is removable or not."
This seems to indicate that external storage need not refer to an actual SD card and could be internal. Therefore, why would I need to size the emulated SD card greater than zero to get that code to work? What am I misunderstanding or missing?
Also, does context.getExternalFilesDir refer to the same directory's flags as Environment.getExternalStorageState?
Thank you,
Tony
You need to choose emulate SD cards to indicate the emulator that you have an external storage associated. And what you said is correct, an external storage can be a removable storage media (such as an SD card) or an internal (non-removable) storage.
Yes, context.getExternalFilesDir returns the absolute path to the directory on the external filesystem as per the documentation, hence refers to the same directory's flags as Environment.getExternalStorageState
In all the devices I have had the sd card has always been mounted on the path /mnt/sdcard (this value is also returned by the function Environment.getExternalStorageDirectory().getAbsolutePath())
Can I consider it as a constant or are there cases in which it is different?
No. You can't consider as Constant its change sometime /sdcard only.So use Environment.getExternalStorageDirectory().getAbsolutePath() for path.
On samsung galaxy s2 /sdcard is phone external memory. micro sd is under /sdcard/external_sd
No , the external storage can be a removable storage media (such as an SD card) or an internal (non-removable) storage.
public void initCache(Context context)
{
this.context = context;
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"myapp");
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
I have the right permission in manifest file and also I have th sd card installed. But in spite of this my app is writing to internal storage. I am using Motorola Atrix.
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 1.x and 2.x.
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.
I have a requirement that I need to copy some files to the SD card programatically.
I have used
Environment.getExternalStorageDirectory()
to refer the SD card but In some devices it is referring to internal memory of the device.
Then I tried "/mnt/sdcard/" this path also still referring to Internal memory of the device.
I have done some investigation and came to know that "Environment.getExternalStorageDirectory()" will refer to internal memory of the device.
But I want to always store my files in SD card for all the devices.
I just want to know the path which should always refer to the Sd card in all the devices.
Is there any hard coded way to do this..??
Please help me.
Android doesn't know anything about the way the data is physically stored (could be a SD card, a CD, a chipset, etc). The only thing it knows is about whether the storage is "internal" or "external" (more details here).
So the way you are doing is fine: if the system gives you a path to an internal chipset when you call getExternalStorageDirectory(), this means that your physical device is built that way. There is no workaround for that.
is it possible to have low level access in Android with Java/NDK to create for example card scanner like scandisk or card defragmenter? I move a lots of stuff around my card and it gets fragmented quickly. I have experience with FAT32 defragmenting on Windows, but I'dliek to do this on Android.
Fragmentation does not affect SD card as much as it affect a harddrive since SD card does not have spinning parts or moving heads, the difference between random access vs sequential access of an SD card is negligible.
In other words, SD card does not need defragmenting; in fact defragmenting an SD card will only lower the life span of your SD card since the memory cells of an SD card have a limit on the number of read/write that you can do on them.
And if you need to "scandisk" (or "fsck" in Unix/Linux-speak, stands for "File System ChecK"), I don't think the Android's default shell comes with fsck, but you should be able to fsck the SD card from your computer.
Maybe this is related to one of my questions.