0

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+?

5
  • "It works as expected on API level 28 and below" -- that is rather surprising, given that insert() doesn't take a Uri like that. It is supposed to be a Uri representing a collection. "Absolute path of my file is" -- I fail to see how that will work with RELATIVE_PATH. In particular, MediaStore has no rights to access that file. Commented Nov 10, 2023 at 14:30
  • @CommonsWare I'm inserting relative path into RELATIVE_PATH. I mentioned absolute path so thay you (or someone else) can see where the file is actually located. Commented Nov 10, 2023 at 14:33
  • That path is not relative to anything meaningful to MediaStore. And, again, MediaStore has no rights to access that file on API Level 29 and higher. Note that getContentUriForPath() was deprecated in API Level 29 for related reasons. Commented Nov 10, 2023 at 14:34
  • @CommonsWare So how should I change my insert then? Commented Nov 10, 2023 at 14:35
  • 1
    Personally, I would create a custom ContentProvider to serve my content, then use that with RingtoneManger. Commented Nov 10, 2023 at 15:02

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.