9

As explained here:

http://www.doubleencore.com/2014/03/android-external-storage/

or here:

http://www.androidpolice.com/2014/02/17/external-blues-google-has-brought-big-changes-to-sd-cards-in-kitkat-and-even-samsung-may-be-implementing-them/

KitKat is limiting writing to the secondary external storage to the package specific directory (although some developers have found a workaround already...). With Samsung using the sdcard as a secondary external storage and rolling out it's 4.4.2 update this has become a major issue for many apps.

My app has a save as function that allows the user to pick an arbitrary directory to save a file to. I'm using Intents like org.openintents.action.PICK_DIRECTORY, com.estrongs.action.PICK_DIRECTORY or my integrated file explorer to pick a directory. The user is of course free to pick any path on the sdcard too but because of the new restrictions with KitKat the actual store operation fails if the directory is one my app has no write access to.

I need an alternative way to pick a directory on KitKat so that the user doesn't get an error message when he/she tries to save to sdcard. That could be achieved by letting them pick only directories the app has write access to.

I tried to use Intent.ACTION_CREATE_DOCUMENT like so:

Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT)
                    .addCategory(Intent.CATEGORY_OPENABLE)
                    .setType(attachment.getContentType())
                    .putExtra(Intent.EXTRA_TITLE, attachment.getName());

startActivityForResult(intent, RequestCodes.MSG_CHOOSE_DIRECTORY);

This works fine and I can write to the file the user picked BUT I only get to pick certain directories. E.g. for a pdf file it will return the download directory (matching Environment.DIRECTORY_DOWNLOADS), for jpg it will allow me to pick the download directory and the Google drive(s). It does however not give me the option to pick other folders on the primary external storage nor the package specific directory on sdcard (I tried different content types like "*/*" or DocumentsContract.Document.MIME_TYPE_DIR but to no avail).

So what I'm looking for is a way to let the user pick a directory on the primary external file system (as in returned by Environment.getExternalStorageDirectory() which is in fact internal storage) plus all the directories the framework would give me access to in the secondary external storage in order to save a file in that directory. Whether the user picks a directory or a file doesn't matter, the app would either use its own file name or the one the user picked.

Alternatively knowing how certain apps found a way around the new write restrictions would of course be a viable option too ;-). ES File Explorer e.g. can write any file to any directory on sdcard as I can confirm from my own tests on an unrooted S4 with sdcard.

Emanuel Moecklin
  • 28,488
  • 11
  • 69
  • 85
  • Have you already set "show advanced devices" in the DocumentsUI settings? –  Mar 29 '14 at 20:41
  • @Nutomic: you might just have saved my day. I have to run some tests on a device with sdcard but at least on my Nexus 5 it now shows internal storage, all Google drives and the Downloads directory. Please write it as an answer and I'll add my code to make it a usable example and you'll get the bounty. – Emanuel Moecklin Mar 30 '14 at 16:55
  • 1
    You got answer for this problem? please post the answer it will be really help full. – Shivaraj Patil Nov 24 '14 at 14:25
  • @EmanuelMoecklin can you please answer this question, i think you can give me a satisfied answer https://stackoverflow.com/questions/58166061/how-to-write-a-file-using-intent-action-create-document – Nasib Sep 30 '19 at 10:33

3 Answers3

1

Have you tried MIME_TYPE_DIR ?

intent.setType(DocumentsContract.Document.MIME_TYPE_DIR);//For API 19+

Edit: Document Provider

xmen
  • 1,947
  • 2
  • 25
  • 47
  • Good thinking but unfortunately it still shows only the same limited number of folders :-( – Emanuel Moecklin Mar 21 '14 at 15:39
  • Then you have write your own document provider. Check edited answer. – xmen Mar 21 '14 at 17:38
  • 2
    Let me get this straight. If I want a simple save as function then I have to implement my own DocumentsProvider which gives me access to all the directories my app has write access to? And that's not just me but every other app that wants to "save as" documents meaning I as a user would then see 10 different DocumentsProvider in the picker app that would allow me to pick a path for my file to save? Can it really be that Google didn't consider a simple use case as this one when they designed the SAF? – Emanuel Moecklin Mar 21 '14 at 18:43
  • Yes it has to be done this way now. Plus you can use other app's document provider too but I wouldn't put my app dependency on them. I would implement my own. Google is known to make life easier, then forces their BS way on both devs and users. – xmen Mar 22 '14 at 01:38
  • Anyone willing to write a "simple" document provider we need now for a simple "save as" function? – Emanuel Moecklin Mar 22 '14 at 02:11
  • Yes I was writing till I found a bug in SAF. Too lazy to report, too lazy to ask question about it. Dont have real device to test. Emulator only have emulated sd card, which android allows to write for all apps. Asked question about it few days back, noone knows. So yea..but if you have real device running 4.4.2 without root and external sdcard then can test my testing app. – xmen Mar 22 '14 at 03:38
  • I have an S4 with sdcard and 4.4.2 and it does have the issue although the latest ES File Explorer can write and delete anywhere on the sdcard so there MUST be a way around this? – Emanuel Moecklin Mar 22 '14 at 03:49
  • ES File Explorer can only write media files, try copying a .rar or any other non-media files to real external. Can it do ? – xmen Mar 22 '14 at 03:55
  • I just copied an apk from the sdcard to another folder on the sdcard and it worked. I guess an apk doesn't qualify as a media file. BTW my S4 is not rooted. – Emanuel Moecklin Mar 22 '14 at 04:03
  • are you sure the target path is real external sdcard ? not built in one. – xmen Mar 22 '14 at 04:06
  • Yes. In Astro File Manager it's mnt/extSDCard, in ES File Explorer it's also extSdCard. If I unmount the sdcard the directory disappears from both file managers. I can also see it on my pc as Card (next to Phone) and on top of that Astro File Manager can't write files to the card (neither can my app). – Emanuel Moecklin Mar 22 '14 at 04:12
  • So I'm very sure they found a way around the limited write permissions. The question is just how. It "should" not be possible on an not-rooted device... – Emanuel Moecklin Mar 22 '14 at 04:14
  • Do you have any messenger ? If have yahoo messenger, check my Profile page. – xmen Mar 22 '14 at 04:33
  • Nope but shouldn't there be a chat function in SO? – Emanuel Moecklin Mar 22 '14 at 04:37
  • You can join http://chat.stackoverflow.com/rooms/50208/room-for-emanuel-moecklin-and-xmen-w-k – Emanuel Moecklin Mar 22 '14 at 04:50
  • Yes, you probably have to do this manually. While Android allows apps access to actual filesystems, it's unfortunately never really considered the idea of a filesystem to be a *user-facing* concept. – Chris Stratton Mar 24 '14 at 16:41
  • @ChrisStratton : Whats wrong with "the idea of filesystem to be user-facing concept" ? PC does same thing, it would be nice a phone does too. Thats one of point of having the smart phone, because they are actually similar to PC. – xmen Mar 25 '14 at 03:21
  • Well, that's a philosophical question. Some of use were like "oh, a unix box that fits in my pocket!" but that vision driving Android seems to be more of a "protect users from themselves" one. Trying to put a linux in that environment isn't a bad challenge to undertake, but it is unfortunate that it was done in a way that does not extended elegantly to the needs of cluefull users. – Chris Stratton Mar 25 '14 at 03:39
  • 4
    Sometimes things turns out to be as never intended. But that doesn't mean it will always be bad. Most of android users like android just because it has many free apps available, and the reason behind many applications was because android used to be very open. Now they keep closing their main feature one by one. Soon it will be same as windows phone and iPhone. Android does allows to user to install APK from outside Google Play, and it warns them before. Couldn't they do same with this ? And all the excuses they coming up with clean and secure, its all moronic. There is something big behind it. – xmen Mar 25 '14 at 04:21
  • please anyone answer this question https://stackoverflow.com/questions/58166061/how-to-write-a-file-using-intent-action-create-document – Nasib Sep 30 '19 at 10:34
1

To see external storage in the DocumentsUI (eg file picker dialog), you have to enable "Show advanced devices" in the DocumentsUI settings.

This is a user setting, so it can only be changed manually by the user.

  • Unfortunately this doesn't work either. It let's me pick directories on primary external storage and all the Google drives but no directory on sdcard ;-(. – Emanuel Moecklin Mar 31 '14 at 02:04
  • Hm sorry, I don't have a physical sdcard myself so I couldn't test that. –  Mar 31 '14 at 08:16
  • Nowadays you could use `intent.putExtra("android.content.extra.SHOW_ADVANCED", true)` which works for me on stock android devices. It might not work if the device producer has replaced the documents app. Also I am not sure if it is an official API and if it will be supported in the future. Google uses it in some of their example code snippets. – tobltobs Nov 30 '19 at 12:40
0

As explained in this in depth article, if you are requesting android.permission.WRITE_EXTERNAL_STORAGE then

the permissions of primary external storage have not changed; they behave the same in 4.4 as they did before.

It is only secondary external storage that is affected by the changes to KitKat - the only directory you have access to on secondary external storage is one dedicated to your app. They also mention that on Samsung devices SD card is considered secondary external storage.

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • My question isn't about permission to the primary external storage which I have. The point is that the user picks a directory to save a file to and if they pick one on the secondary external storage then my app can't write the file (unless it's in the package specific directory) and there's nothing I can do. This means I can't use my "old" way to pick a directory but have to use the new Picker which would NOT return directories I have no access to. – Emanuel Moecklin Mar 21 '14 at 02:52
  • Are you saying an `ACTION_PICK` is allowing you to select directories from the secondary external storage? – ianhanniballake Mar 21 '14 at 02:55
  • No I'm using other actions to pick a directory. Please read my edited question. – Emanuel Moecklin Mar 21 '14 at 03:01