How to bring up list of available notification sounds on Android

JavaAndroidAudioNotifications

Java Problem Overview


I'm creating notifications in my Android application, and would like to have an option in my preferences to set what sound is used for the notification. I know that in the Settings application you can choose a default notification sound from a list. Where does that list come from, and is there a way for me to display the same list in my application?

Java Solutions


Solution 1 - Java

Just copy/pasting some code from one of my apps that does what you are looking for.

This is in an onClick handler of a button labeled "set ringtone" or something similar:

Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Select Tone");
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null);
this.startActivityForResult(intent, 5);

And this code captures the choice made by the user:

@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
    if (resultCode == Activity.RESULT_OK && requestCode == 5) {
        Uri uri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);

        if (uri != null) {
            this.chosenRingtone = uri.toString();
        } else {
            this.chosenRingtone = null;
        }
    }            
}

Also, I advise my users to install the "Rings Extended" app from the Android Market. Then whenever this dialog is opened on their device, such as from my app or from the phone's settings menu, the user will have the additional choice of picking any of the mp3s stored on their device, not just the built in ringtones.

Solution 2 - Java

Or just stick this in your preferences XML:

  <RingtonePreference android:showDefault="true"
     android:key="Audio" android:title="Alarm Noise"
     android:ringtoneType="notification" />

Full content of my sample XML just for context:

<?xml version="1.0" encoding="UTF-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference android:title="Some value"
				    android:key="someval"
				    android:summary="Please provide some value" />
<EditTextPreference android:title="Some other value"
				    android:key="someval2"
				    android:summary="Please provide some other value" />
 <RingtonePreference android:showDefault="true"
     android:key="Audio" android:title="Alarm Noise"
     android:ringtoneType="notification" />

</PreferenceScreen>

Solution 3 - Java

This is the method I use to get a list of notification sounds available in the phone :)

public Map<String, String> getNotifications() {
    RingtoneManager manager = new RingtoneManager(this);
    manager.setType(RingtoneManager.TYPE_NOTIFICATION);
    Cursor cursor = manager.getCursor();

    Map<String, String> list = new HashMap<>();
    while (cursor.moveToNext()) {
        String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
        String notificationUri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX);

        list.put(notificationTitle, notificationUri);
    }
    
    return list;
}

EDIT: This is for the comment regarding how to set the sound in the NotificationCompat.Builder. This method instead gets the ringtone's ID which is what the phone uses, instead of the human readable TITLE the other method got. Combine the uri and the id, and you have the ringtones location.

public ArrayList<String> getNotificationSounds() {
    RingtoneManager manager = new RingtoneManager(this);
    manager.setType(RingtoneManager.TYPE_NOTIFICATION);
    Cursor cursor = manager.getCursor();

    ArrayList<String> list = new ArrayList<>();
    while (cursor.moveToNext()) {
        String id = cursor.getString(RingtoneManager.ID_COLUMN_INDEX);
        String uri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX);
        
        list.add(uri + "/" + id);
    }

    return list;
}

The above code will return a list of strings like "content://media/internal/audio/media/27".. you can then pass one of these strings as a Uri into the .setSound() like:

.setSound(Uri.parse("content://media/internal/audio/media/27"))

Hope that was clear enough :)

Solution 4 - Java

  public void listRingtones() {
            RingtoneManager manager = new RingtoneManager(this);
            manager.setType(RingtoneManager.TYPE_NOTIFICATION);
           // manager.setType(RingtoneManager.TYPE_RINGTONE);//For Get System Ringtone
            Cursor cursor = manager.getCursor();
    
            while (cursor.moveToNext()) {
                String title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
                String uri = manager.getRingtoneUri(cursor.getPosition());
    
                String ringtoneName= cursor.getString(cursor.getColumnIndex("title"));


    
                Log.e("All Data", "getNotifications: "+ title+"-=---"+uri+"------"+ringtoneName);
                // Do something with the title and the URI of ringtone
            }
        }

Solution 5 - Java

Here's another approach (in Kotlin), build from other answers in this question, that allows you to specify the name of the tone, and then play it:

fun playErrorTone(activity: Activity, context: Context, notificationName: String = "Betelgeuse") {

    val notifications = getNotificationSounds(activity)

    try {
        val tone = notifications.getValue(notificationName)
        val errorTone = RingtoneManager.getRingtone(context, Uri.parse(tone))
        errorTone.play()
    } catch (e: NoSuchElementException) {
        try {
            // If sound not found, default to first one in list
            val errorTone = RingtoneManager.getRingtone(context, Uri.parse(notifications.values.first()))
            errorTone.play()
        } catch (e: NoSuchElementException) {
            Timber.d("NO NOTIFICATION SOUNDS FOUND")
        }
    }
}

private fun getNotificationSounds(activity: Activity): HashMap<String, String> {
    val manager = RingtoneManager(activity)
    manager.setType(RingtoneManager.TYPE_NOTIFICATION)
    val cursor = manager.cursor

    val list = HashMap<String, String>()
    while (cursor.moveToNext()) {
        val id = cursor.getString(RingtoneManager.ID_COLUMN_INDEX)
        val uri = cursor.getString(RingtoneManager.URI_COLUMN_INDEX)
        val title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX)

        list.set(title, "$uri/$id")
    }

    return list
}

It can probably take some refactoring and optimization, but you should get the idea.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionrobintwView Question on Stackoverflow
Solution 1 - JavaMark BView Answer on Stackoverflow
Solution 2 - JavaJD.View Answer on Stackoverflow
Solution 3 - JavaMurphybro2View Answer on Stackoverflow
Solution 4 - JavaManthan PatelView Answer on Stackoverflow
Solution 5 - JavaNicolai HarboView Answer on Stackoverflow