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 adding the
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 denied)”-flavored
FileNotFoundException entries in your logs when trying to access external storage.
If you hold
WRITE_EXTERNAL_STORAGE, you do not need to also hold
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
ContentProvider 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
ContentProvider that returns
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
android:minSdkVersion yet still catch any places where you might have messed up and used too-new APIs without a version guard block in place.