6

I have spent literally hours now looking for (and trying) many different ways to write some files to my 4.4 Android KitKat's removable SD card after getting countless "eacces permission denied" errors. Seems now that Google has limited access to the filesystem on SD cards you are forced to only be able to write to directories owned by the application (eg: /Android/data/com.mycompany.myapp/files/).

Finally I was able to get something working that creates a directory on the removable SD card that can be written to. However I am curious why in order to gain access to this owned directory on the removable SD card I first had to create a new file object using a path to the external directory?

My implementation:

First I create two globals to house the strings of both the external and removable paths.

MainActivity

public class MainActivity extends ActionBarActivity {
    String externalStorageDirectory;//path to owned external storage files
    String secondaryStorageDirectory ;//path to owned removable storage files

Then I ask the system what the manufacturer specific directories are called and start concatenating absolute paths for both the externalStorage and removableStorage variables. I also create a new File object initialized with the path to the external app owned directory.

onCreate()

externalStorageDirectory = this.getExternalFilesDir(null).toString();//build absolute path to the app owned external directory
File folder = new File(externalStorageDirectory ); //THIS LINE IS CRUCIAL!!
Log.d("DEBUG", " - External Path" + externalStorageDirectory );// "/storage/emulated/0/Android/data/com.mycompany.myapp/files"


String ownedDirectory = "/Android/data/" + this.getPackageName() + "/files/";
secondaryStorageDirectory = System.getenv("SECONDARY_STORAGE").toString() + ownedDirectory;//build absolute path to the app owned removable directory
Log.d("DEBUG", " - Removable Path"+secondaryStorageDirectory );// "/storage/external/Android/data/com.mycompany.myapp/files/"

Finally I was able to write a file to my application's owned removable SD card directory. And more specifically I was using an AsyncTask to download my files and save them, method #1 of this post.

doInBackground()

output = new FileOutputStream(secondaryStorageDirectory + "myawesomefile.mp4");

Then I was able to navigate to the removable SD card directory via adb shell and I could see my file.

Adb shell output:

//internal storage
shell@QTAQZ3:/storage/emulated/0/Android/data/com.mycompany.myapp/files $ ls
s                                                                             <

//removable SD card
shell@QTAQZ3:/storage/external/Android/data/com.mycompany.myapp/files $ ls
ls
myawesomefile.mp4        
                                                                   <

And just to reiterate a little:

File folder = new File(externalStorageDirectory); //THIS LINE IS CRUCIAL!!
File folder = new File(secondaryStorageDirectory ); //THIS LINE DOES NOTHING?

So my questions are:

  • When I create that File object instance, what is happening that makes those directories available?
  • Why is having to call mkdir() or mkdirs() seem to unnecessary in this case as the dirs magically appear when the file object was created?
  • And why am I able to see my app's secondary(removable) directory only after I set the file to the external(non-removable) path?

Admittedly I am relatively new to Android programming, so I'm not even sure if this approach is correct or just a lucky hack? But it seems to work in my app for now.

Community
  • 1
  • 1
Logic1
  • 1,806
  • 3
  • 26
  • 43
  • Please have a look at getExternalFilesDirs(). ....Dirssss...! Please tell exactly all values. Also of the two paths you talked about. Please show full code how you write content to a file. Do not force us to read other posts. – greenapps Jun 28 '15 at 09:01
  • 'internalStorageDirectory = this.getExternalFilesDir(nu..' Please do not rename external to internal. Very confusing. Android devices have internal and external memory. If you can put in a micro SD card it has removable memory too. Or secondary external if you want. – greenapps Jun 28 '15 at 09:04
  • As there is also a funtion getExternalStorageDirectory() your renaming from FilesDir to Storage is even worse. – greenapps Jun 28 '15 at 09:06
  • 'first I create two globals to house the strings of both the internal and external paths.'. Not needed. You can determine them when needed. Only if you want to create your own directories on them you could make globals for the full paths of those directories. – greenapps Jun 28 '15 at 09:09
  • @greenapps Hey, thanks for pointing out the typos where internal = external.. lol. I renamed those variables and updated my post. Also i would have loved to have posted more code related to my AsyncTask configuration but i thought it was a bit much and a little out of context for this question. Also thanks, I will be taking a look at getExternalFilesDirs() – Logic1 Jun 28 '15 at 09:38
  • Did you find the solution ? – Mohamed Mar 24 '16 at 20:47
  • I did get some functionality but Im on to android 5 now. I think 4.4.2 was kind of bugged.. – Logic1 Mar 25 '16 at 01:44

0 Answers0