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.
However:
-
You do not appear to be grandfathered into this permission based on
android:targetSdkVersion
orandroid:minSdkVersion
, as was the case whenWRITE_EXTERNAL_STORAGE
was 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
Uri
values from anIntent
or aContentProvider
query – using aContentResolver
to open afile://
Uri
means that you need this permission, as was discussed in anandroid-developers
thread.
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 content://
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 file://
Uri
values, consider switching to returning
content://
Uri
values that point back to your ContentProvider
and 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.