Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pick a directory/file using Intent.ACTION_CREATE_DOCUMENT (Storage Access Framework)

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.

like image 708
Emanuel Moecklin Avatar asked Mar 21 '14 02:03

Emanuel Moecklin


People also ask

How do I use scoped storage in Android 11?

To enable scoped storage in your app, regardless of your app's target SDK version and manifest flag values, enable the following app compatibility flags: DEFAULT_SCOPED_STORAGE (enabled for all apps by default) FORCE_ENABLE_SCOPED_STORAGE (disabled for all apps by default)


1 Answers

Have you tried MIME_TYPE_DIR ?

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

Edit: Document Provider

like image 151
xmen Avatar answered Oct 20 '22 00:10

xmen