Support for SD Card on Android 6.0 (Marshmallow)
December 7, 2015
Since Android 4.4 (KitKat) Google keeps making significant changes in how apps can access the removable SD card. In KitKat apps cannot write to folders on SD card. In Android 5.x (Lollipop) there is a new way to write to the SD card, albeit with poor user experience and bad performance.
Android 6.0 (Marshmallow) officially does not introduce new restrictions in SD card access, but it breaks
the current API semantics in a subtle way. To delete a file /storage/35A5-BE41/foo/bar.txt
on SD card,
we are supposed to use code like this
DocumentFile fooDir = DocumentFile.fromTreeUri(context, fooTreeUri);
DocumentFile barFile = fooDir.findFile("bar.txt");
boolean deleted = barFile.delete(); // => true
boolean exist = (new File("/storage/35A5-BE41/foo/bar.txt")).exists(); // => true !!
DocumentFile.delete()
is supposed to return true
if the file was deleted, otherwise false
. That’s
what its javadoc says and on a par with what normal File.delete()
returns. But if we check for the
existence of the file right after seeing deleted == true
we’d see it still exists. It’s not the code.
If we watch the SD card filesystem we’d indeed see bar.txt
really is still there.
What happened? On Marshmallow DocumentFile.delete()
is asynchronous. It returns success (true
)
immediately but the file was only enqueued for deletion. bar.txt
is truly gone only after about 10
seconds. That’s when the parent folder contains nothing else, only this one file. If there is a lot
of files there the delay can be much longer. This behavior is clearly a breakage of the official
DocumentFile.delete()
contract.
I have a workaround for Dropsync, OneSync, Autosync for Google Drive, and Autosync for Box. The beta versions are available in Play Store beta channel if you can’t wait. The workaround should work quite well, but I want to work on it some more to minimize the negative impact on sync speed.
Besides this issue Marshmallow also breaks local file change monitoring. Instant upload feature uses
FileObserver
API class to monitor changes in selected folders. The system notifies registered apps
when files are modified, deleted or added. This does not work anymore on Marshmallow. Apps don’t receive
any notifications. Not for changes in folders on SD card, not even for changes in folders in device internal
storage. There is a bug report
filed against Android 6.0 preview. It was closed when 6.0 final was released but obviously without the bug
being fixed. Until it’s fixed, Instant Upload in my sync apps does not work and unfortunately it seems
there is nothing I can do about it. This is a system level bug which apps cannot workaround.