Some of my users have reported to Google Play the following error when trying to select a ringtone in my app. (there's more to it, but it's not relevant)
java.lang.SecurityException: Permission Denial:
reading com.android.providers.media.MediaProvider
uri content://media/external/audio/media
from pid=5738, uid=10122 requires android.permission.READ_EXTERNAL_STORAGE
I assume this issue is happening due to certain tones that are on external storage. I don't want to include the READ_EXTERNAL_STORAGE
permission in my app unless I absolutely have to.
Is there a way to circumvent the issue and just exclude any tones that may be on the external storage?
Note: I'm getting ringtones with RingtoneManager
and convert them between String
and Uri
. No other code is touching the user's media.
Also, I do not have a line number since the stacktrace is from obfuscated code and re-mapping the stack trace did not provide line number.
On the Settings > Privacy > Permission manager > Files and media page, each app that has the permission is listed under Allowed for all files. If your app targets Android 11, keep in mind that this access to "all files" is read-only.
To read and write data to external storage, the app required WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE system permission. These permissions are added to the AndroidManifest. xml file. Add these permissions just after the package name.
When an app is granted storage permission, it can access the device storage at any time. This means it can upload personal files or even delete sensitive information from the device, so it's better to think twice before giving storage permission to untrusted apps, as it can be harmful.
Just had the same problem and came up with the following solution:
private Cursor createCursor()
{
Uri uri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
String[] columns = new String[]
{
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.TITLE_KEY
};
String filter = createBooleanFilter(MediaStore.Audio.AudioColumns.IS_ALARM);
String order = MediaStore.Audio.Media.DEFAULT_SORT_ORDER;
return getContext().getContentResolver().query(uri, columns, filter, null, order);
}
private String createBooleanFilter(String... columns)
{
if(columns.length > 0)
{
StringBuilder sb = new StringBuilder();
sb.append("(");
for(int i = columns.length - 1; i > 0; i--)
{
sb.append(columns[i]).append("=1 or ");
}
sb.append(columns[0]);
sb.append(")");
return sb.toString();
}
return null;
}
To get the Uri of a ringtone you need to combine the INTERNAL_CONTENT_URI
with the _ID
column value, you can do this by using ContentUris
class:
Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, cursor.getLong(0));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With