Think About READ_EXTERNAL_STORAGE Now
Now that more Jelly Bean devices are cropping up, you really need
to think about setting your build target to API Level 16 and
READ_EXTERNAL_STORAGE permission to your application
if you read (and do not write) from external storage.
Users of Jelly Bean devices can go into Developer Options in the Settings app and check the “Protect USB storage” preference. In theory, only developers will do this. In practice, other people will do so. After all, who wouldn’t want to protect their USB storage? Besides, the confirmation dialog that appears when checking that preference says “some apps may not work until updated by their developers”, putting the blame on lazy developers.
Hence, even before this protection is enabled by default –
perhaps as early as the “K” release – a tiny percentage of your
users will check this checkbox, and a subset of them will
blame you if your app does not work. You will see “EACCES (Permission
FileNotFoundException entries in your
logs when trying to access external storage.
If you hold
WRITE_EXTERNAL_STORAGE, you do not need to also
READ_EXTERNAL_STORAGE – write implies read, in this case.
You do not appear to be grandfathered into this permission based on
android:minSdkVersion, as was the case when
WRITE_EXTERNAL_STORAGEwas added a long time ago. Hence, all apps reading (but not writing) external storage will need this permission.
The 4.1 emulator appears broken, insofar as it does not check the Developer Options preference, and therefore grants access to external storage even if you lack the permission. The R20.0.1 patch release to the tools does not seem to fix this. I have filed an issue about this problem.
The problem affects apps that might not realize that they are reading files from external storage, because they are being handed
Urivalues from an
ContentProviderquery – using a
ContentResolverto open a
Urimeans that you need this permission, as was discussed in an
Note, though, that the permission needs to be held by the process
opening the file, not the one reading it. Hence, a
that serves files from external storage via
openFile(), and is accessed
by consumers via
Uri values, will work fine if the
ContentProvider has the permission – the consumer does not need it
in that case. Hence, if you implement a
Uri values, consider switching to returning
Uri values that point back to your
openFile(), as that will prevent your content from fouling up
other apps that have not yet added this permission.
The biggest issue for some is that you have to switch to a build target
of API Level 16 for the toolchain to recognize this permission.
Fortunately, the improvements in Lint make it much easier to have
your build target set higher than your
still catch any places where you might have messed up and used
too-new APIs without a version guard block in place.
Stuck on an Android problem? Subscribers have access to live office hours chats with Mark Murphy, to help you work through your challenges!