After going through the headache of figuring out how to make a large SD card (~32gb) using mksdcard and pushing information to it (slowly) using ADB, I can go on to my AVD manager, start up my Nexus 4 (with all default settings), and go to
Settings > Device > Storage & USB > Portable Storage > SDCARD
I see all of the files I expect to see there (i.e. all the default stuff plus everything I pushed).
However, in my app, it tells me there's nothing there. I have a menu item that calls this simple function, but its results are baffling.
public void dumpSDCardContents(MenuItem m) {
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
recursFiles(Environment.getExternalStorageDirectory());
}
}
private void recursFiles(File dir){
System.out.println("Now scanning " + dir.getAbsolutePath());
File[] listFiles = dir.listFiles();
if(listFiles != null){
for(File file : listFiles){
System.out.println(file.getAbsolutePath());
if(file.isDirectory()){
recursFiles(file);
}
}
} else {
System.out.println("That directory has nothing in it.");
}
}
All I see in logcat is
Now scanning /storage/19E8-1D10
That directory has nothing in it.
Which is bollocks. If I go to the File Explorer tab in DDMS, I can see the web of linking from /mnt/sdcard/ to /sdcard/ to /storage/self/primary/ to /mnt/user/0/primary/ to (finally) /storage/19E8-1D10/ and then looking in that directory, plain as day, is all the data I'm looking for.
I was sure to add
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
to my AndroidManifest.xml, and besides, the javadoc comment on Environment.MEDIA_MOUNTED (which I already successfully tested against) says "Storage state if the media is present and mounted at its mount point with read/write access."
What am I missing here???
-
UPDATE:
So I changed the recursFiles function to dump file permissions
private void recursFiles(File dir){
System.out.println("Now scanning " + dir.getAbsolutePath());
System.out.println("Can r dir? " + dir.canRead());
System.out.println("Can w dir? " + dir.canWrite());
System.out.println("Can x dir? " + dir.canExecute());
File[] listFiles = dir.listFiles();
if(listFiles != null){
for(File file : listFiles){
System.out.println(file.getAbsolutePath());
if(file.isDirectory()){
recursFiles(file);
}
}
} else {
System.out.println("That directory has nothing in it.");
}
}
and (not terribly surprisingly given the original output) it tells me
Now scanning /storage/17F2-2913
Can r dir? false
Can w dir? false
Can x dir? true
That directory has nothing in it.
So. Why would the Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) check come back true (implying I have both read and write) when I in fact have neither read nor write permissions??
And how do I fix this?
I noticed when I went into the emulator using adb shell, that permissions files (i.e. /system/etc/permissions/platform.xml and /etc/permissions/platform.xml) flat out don't even have a permission tag for WRITE_EXTERNAL_STORAGE.
How do I rectify all this??
Related
I use this code to get folder of removable SD-card:
var baseDir = Environment.getExternalStorageDirectory().absolutePath
val dirs = getExternalFilesDirs(null)
for (file in dirs){
if(Environment.isExternalStorageRemovable(file)) {
baseDir = file.absolutePath
val idx = baseDir.indexOf("/Android/")
if(idx > 0) {
baseDir = baseDir.substring(0,idx)
break
}
}
}
And it work well enough, at least on test devices. After this code baseDir contain something like /storage/AB96-CD85. But when I try to make dir, I always get false result:
baseDir = baseDir + java.io.File.separator + name
var result: File? = null
if (Environment.getExternalStorageState() != Environment.MEDIA_MOUNTED) {
Log.e(TAG, "SD-card not mounted.")
return result
}
val dir = File(baseDir)
if (!dir.exists()) {
if (!dir.mkdir()) {
Log.e(
TAG,
"Can't create directory $name"
)
return result
}
}
minSdkVersion is 21. Before this code execution I've already requested WRITE_EXTERNAL_STORAGE permission and got positive response from user. I wrote permission block in Manifest in correct place (out of <application></application> block). The code above create folder without any problems on one device and cannot do the same on other (in the same time ES File manager work well on sdcard). What was tried:
App re-installation
Phone restart
Even unplag USB cable
Storage Access Framework(SAF)
What I should do to make mkdir() function work on the second device?
If I should add some other permission or move user to some system settings screen, how can I do that?
Why code above work on one device and doesn't work on other?
I think it's about different Android versions.
To modify External SD card's filesystem, you need to get "special permision".
You can Google some libraries, that do it automatically. Just use one of these and you will gain that "special permission". It's weird but WRITE_EXTERNAL_STORAGE not providing you access to SD Card, only to eMMC memory.
I am really tired with debugging this problem. I have an application that writes to a storage. The application worked fine, until I got an update (I don't know which update caused it, because I had a break from Android development) - my Android version is 6.0.1 now.
Anyways I am trying to write to my external storage. I got prepared reading the new permission system for Android, got the permissions, and I am doing a check in my code:
checkSelfPermission("android.permission.READ_EXTERNAL_STORAGE")
checkSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE")
By debugging I've checked (I also get a code that checks and asks if permission is necessary, but I wanted to be sure that it really is ;) ) I've observed that they return value 0, which is equal to PackageManager.PERMISSION_GRANTED
So, the permissions are granted for sure. I am trying to create an App directory in the storage to write pdf files, store sqlite DB and stuff like that.
Here is how I create the directory:
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
File dir = Environment.getExternalStorageDirectory();
String sNewDir = Constants.ApplicationDataDir;
if (sSubDir == null) {
sSubDir = "";
} else {
sSubDir = sSubDir.trim();
}
if (sSubDir.length() > 0) {
sNewDir += File.separator + sSubDir;
}
File dirName = new File(dir, sNewDir);
if (!dirName.exists()) {
if (!dirName.mkdirs()) {
LogDump.e("getAppDirectory err", " (sSubDir=<" + sSubDir + "> cannot create dir: " + dirName.getAbsolutePath());
}
}
return dirName;
} else {
// Something else is wrong
LogDump.e("getAppDirectory err", " (sSubDir=<" + sSubDir + "> not mounted state: " + state);
return null;
}
The value of dirName is /storage/emulated/0/MY_APP_CONST_VALUE/sSubDir (the sSubdir is a parameter for subdirectory ie. "Preferences")
Soo, the code (checking with debugger) the execution checks that the directory does not exist, and the mkdirs() returns false result. THAT actually means that the directory does not exist, and could not be created.
During my application operation my logs get filled with:
W/FileUtils: Failed to chmod(/storage/emulated/0/MY_APP_CONST_VALUE/DB/pcdrdata.sqlite3): android.system.ErrnoException: chmod failed: EPERM (Operation not permitted)
from the SQLLite code
And FileNotFound exception for any other file operations...
This seems quite logical since It cannot create the directories, right?
Now for the most confusing part:
I am using total commander, and I can see that the directories are actually being created, the sqlite database is being copied, and all the files that do FileNotFoundException are there. I made a test, deleted them, rerun the App, and they are copied to the location once again. However any read operation on the files is not possible.
So it somehow creates the directories, allows to write (even thouh mkdirs() says otherwise) to them, but does not allow to read.
I am really confused, and tired of trying. I also tried the same without the SD card - identical results though.....
My application creates PDF files - they are created successful, but even the Total Commander says that it cannot open them....
My phone is Xperia Z3
As of KitKat you can't read from the root of the external storage anymore. You can only read in special public directories or in your own private directory on the sdcard. If you're seeing them created but not able to alter them, it seems like Android decided you could write there but not read there
I am new to android development and I have tried to read a directory from my sd card but didn't got succeeded. Below is the code which I wrote to achieve it
File sdcard = Environment.getExternalStorageDirectory();
if(sdcard.exists()) {
Log.d("Sd card", "Sd card exist");
File[] file_names = sdcard.listFiles();
for(File x : file_names) {
Log.d("File Name",x.getName());
}
}
Control passed the if condition and then I got an NullPointerException at "for each" loop line. Probably function sdcard.listFiles() is returning null. I have an Sd card with many folders and files. Actually I have to create a directory file object for directory "Attachments" which is available on my sd card. I also tried the following code to achieve the same.
File file = new File(android.os.Environment.getExternalStorageDirectory() + File.separator + "Attachments");
and
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "Attachments");
on both code when I called the function file.exists(), it returned false.
I have also checked whether sd card is mounted or not by the following code.
String sdCardAvail = Environment.getExternalStorageState();
if(sdCardAvail.equals(Environment.MEDIA_MOUNTED))
Log.d("Card status", "Sd card Available");
The above code has printed "Sd card Available" at log cat.
So please help me out to know whether I am doing it correct or missing any thing.
Thanks....
In order to read or write files on the external storage, your app must acquire the READ_EXTERNAL_STORAGEorWRITE_EXTERNAL_STORAGE system permissions. For example:
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
If you need to both read and write files, then you need to request only the WRITE_EXTERNAL_STORAGE permission, because it implicitly requires read access as well.
Also See This Documentation. It Will solve all your future regarding Storage problems.
I have an application that performs a write operation on an external SD Card (external as in not the "external" in the device's flash memory), but as it has been thoroughly discussed here and in quite a few other questions, it appears there is no generic way / supported API to retrieve an SD Card mounting point that works on every phone, from different manufacturers.
With that in mind, something like the code below needs to be done to find out if an external storage device is mounted and where:
final String state = Environment.getExternalStorageState();
if ( Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) ) { // we can read the External Storage...
//Retrieve the primary External Storage:
final File primaryExternalStorage = Environment.getExternalStorageDirectory();
//Retrieve the External Storages' root directory:
final String externalStorageRootDir;
if ( (externalStorageRootDir = primaryExternalStorage.getParent()) == null ) { // no parent...
Log.i("SD Card Path", "External Storage: " + primaryExternalStorage + "\n");
}
else {
final File externalStorageRoot = new File( externalStorageRootDir );
final File[] files = externalStorageRoot.listFiles();
for ( final File file : files ) {
if ( file.isDirectory() && file.canRead() && (file.listFiles().length > 0) ) { // it is a real directory (not a USB drive)...
Log.i("SD Card Path", "External Storage: " + file.getAbsolutePath() + "\n");
}
}
}
}
I could be wrong, but I understand the SD Card could be completely empty and that last condition (file.listFiles().length > 0) could return false. So I thought, instead of checking that length, I would add file.canWrite(). That worked as I expected on the phone I am currently testing on (Motorola Atrix MB860 - it's old, I know, but one of my requirements is make it compatible with versions starting from Gingerbread, API 9), but I am unsure whether or not that condition could return true to /mnt/asec/ or /mnt/obb on other phones , recent or not, since their both readable directories, thus also satisfying the first two conditions (and could even return true to (file.listFiles().length > 0) if it had something written on it (like a 50MB+ size file on /mnt/obb).
So, in short, what I need to know is whether an app will ever have write permission to these two locations or if only the system has such permission. If yes, what else can I check for in order to exclude them from the final path I wish to obtain: the external SD Card installed on the device?
Thank you in advance for any help!
This is the output on a Nexus 5
shell#hammerhead:/ $ ls -la /mnt/
drwxr-xr-x root system 1970-09-18 01:42 asec
drwx------ media_rw media_rw 1970-09-18 01:42 media_rw
drwxr-xr-x root system 1970-09-18 01:42 obb
as you can see only root has write permission on the directory. So the only way an app can write that directory is to be executed as root
I have a Samsung Nexus S device with android 4.0 loaded on it. I am trying to create a file in an existing folder on sdcard and get a "permission denied". In the following code, exists() returns true but canWrite() returns false. Why?
File exst = Environment.getExternalStorageDirectory();
String exstPath = exst.getPath();
File d = new File(exstPath+"/TestDir/");
if (!d.exists())
{
int b = 1;
}
if (!d.canWrite())
{
int a = 1;
}
By the way, I've added <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> to the manifest but that did not help.
Is your phone plugged into your computer? If so, the computer will take control of the SD card and not allow it to be written to. Try changing the connection mode to 'Charge Only' if this is the case.
Append getAbsolutePath() to your first line, then it should work:
File exst = Environment.getExternalStorageDirectory().getAbsolutePath();
Update:
Reviewing my own code and other SO answers, I believe you do not use canWrite to check if a path is writable on a SD card. Instead you use Environment.MEDIA_MOUNTED:
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
Log.d("Test", "sdcard mounted and writable");
}
else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
Log.d("Test", "sdcard mounted readonly");
}
else {
Log.d("Test", "sdcard state: " + state);
}
Although all the answers give partial suggestions, the problem is very likely Samsungs non-standard implementation of the API
String myPath = Environment.getExternalStorageDirectory().getAbsolutePath ;
// or .getName() or .getPath() <-- these don't return everything you need.
// same is true for the file version you're trying.
// you have to append
"/external_sd/"
to the path before the file name.
Here's Samsungs explanation for their "breaking" of the API
http://developer.samsung.com/forum/board/thread/view.do?boardName=GeneralB&messageId=162934&messageNumber=1381&startId=zzzzz~&searchType=TITLE&searchText=sdcard
it's also mentioned in several SO posts, but I don't have the links handy...
H
[Edit Mid May, 2013] Here's the pathology of this problem: you can get the path() by the various normal methods mentioned. Then, just write a simple file and watch it show up in the DDMS file explorer. Try hardcoding that exact path and file name OR use the /external_sd/ thing - in both cases, you will not be able to read your own file back in ! (Or you might, but it will contain garbage.) We've verified this on three different S3 phones. Will test more on Samsungs "real" phones via their RemoteTestingLab site and report back.