Here's my code. It works as expected on API level 28 and below, but not on 29 and higher.
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
values.put(MediaStore.Audio.Media.DATA, myFile.getAbsolutePath());
} else {
values.put(MediaStore.Audio.Media.RELATIVE_PATH, "Alarms/" + myFile.getName());
}
values.put(MediaStore.Audio.Media.DISPLAY_NAME, myFile.getName());
values.put(MediaStore.Audio.Media.TITLE, myFile.getName());
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mp3");
} else {
values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg");
}
values.put(MediaStore.Audio.Media.SIZE, myFile.length());
values.put(MediaStore.Audio.Media.ARTIST, R.string.app_name);
values.put(MediaStore.Audio.Media.IS_RINGTONE, false);
values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
values.put(MediaStore.Audio.Media.IS_ALARM, true);
values.put(MediaStore.Audio.Media.IS_MUSIC, false);
Uri uri = MediaStore.Audio.Media.getContentUriForPath(myFile.getAbsolutePath());
int cnt = contentResolver.delete(uri, MediaStore.Audio.Media.DISPLAY_NAME + " = ?", new String[]{myFile.getName()});
Uri newUri = contentResolver.insert(uri, values);
//contentResolver.openFileDescriptor(newUri, "r");
RingtoneManager.setActualDefaultRingtoneUri(getApplicationContext(), TYPE_ALARM, newUri);
Absolute path of my file is: /storage/emulated/0/Android/data/some.package/files/Alarms/myFile.mp3
Both delete and insert seem to finish correctly. Value of newUri#toString is something like: content://media/external_primary/audio/media/39
Any attempt thereafter to open the file/descriptor (e.g. commented line) fails on this exception: java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
An attempt to set this file as alarm logs this:
W Failed to open directly; attempting failover: java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
W Failed to cache ringtone: java.io.IOException: java.lang.SecurityException: Uri is not ringtone, alarm, or notification: content://0@media/external_primary/audio/media/39
(It doesn't actually fail & in Alarm application I see name of my file, but the played alarm sound is some default alarm sound, not my sound. Almost looks like as if values get inserted into contentResolver correctly, but reference to my file is somehow invalid.)
How do I adjust this code to make it work on API level 29+?
insert()doesn't take aUrilike that. It is supposed to be aUrirepresenting a collection. "Absolute path of my file is" -- I fail to see how that will work withRELATIVE_PATH. In particular,MediaStorehas no rights to access that file.MediaStore. And, again,MediaStorehas no rights to access that file on API Level 29 and higher. Note thatgetContentUriForPath()was deprecated in API Level 29 for related reasons.ContentProviderto serve my content, then use that withRingtoneManger.