I have sounds in my /raw folder and I would like my user to be able to choose one sound in preferences exactly like RingtonePreference does but only with my sounds.
The preference option doesn't exist anymore. You will need to right click the res -> new -> Android resource file and choose the resource type as xml in the dropdown. Then you will manually need to add the layout for preference xml.
A Preference is the basic building block of the Preference Library. A settings screen contains a Preference hierarchy. You can define this hierarchy as an XML resource, or you can build a hierarchy in code. The sections below describe how to build a simple settings screen using the AndroidX Preference Library.
Here my RingtonePreference replacement. All system ringtones and your custom ringtones (defined in xml, stored in res/raw) are listed:
ExtraRingtonePreference.java
package de.almisoft.test;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import de.almisoft.test.R;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.preference.DialogPreference;
import android.util.AttributeSet;
public class ExtraRingtonePreference extends DialogPreference {
private Context mContext;
private String mValue;
private Ringtone ringtone;
private int mRingtoneType;
private boolean mShowSilent;
private boolean mShowDefault;
private CharSequence[] mExtraRingtones;
private CharSequence[] mExtraRingtoneTitles;
public ExtraRingtonePreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ExtraRingtonePreference, 0, 0);
mRingtoneType = a.getInt(R.styleable.ExtraRingtonePreference_ringtoneType, RingtoneManager.TYPE_RINGTONE);
mShowDefault = a.getBoolean(R.styleable.ExtraRingtonePreference_showDefault, true);
mShowSilent = a.getBoolean(R.styleable.ExtraRingtonePreference_showSilent, true);
mExtraRingtones = a.getTextArray(R.styleable.ExtraRingtonePreference_extraRingtones);
mExtraRingtoneTitles = a.getTextArray(R.styleable.ExtraRingtonePreference_extraRingtoneTitles);
a.recycle();
}
public ExtraRingtonePreference(Context context) {
this(context, null);
}
public String getValue() {
return mValue;
}
private Map<String, Uri> getSounds(int type) {
RingtoneManager ringtoneManager = new RingtoneManager(mContext);
ringtoneManager.setType(type);
Cursor cursor = ringtoneManager.getCursor();
Map<String, Uri> list = new TreeMap<String, Uri>();
while (cursor.moveToNext()) {
String notificationTitle = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
Uri notificationUri = ringtoneManager.getRingtoneUri(cursor.getPosition());
list.put(notificationTitle, notificationUri);
}
return list;
}
private Uri uriFromRaw(String name) {
int resId = mContext.getResources().getIdentifier(name, "raw", mContext.getPackageName());
return Uri.parse("android.resource://" + mContext.getPackageName() + "/" + resId);
}
private String getExtraRingtoneTitle(CharSequence name) {
if (mExtraRingtones != null && mExtraRingtoneTitles != null) {
int index = Arrays.asList(mExtraRingtones).indexOf(name);
return mExtraRingtoneTitles[index].toString();
}
return null;
}
@Override
public CharSequence getSummary() {
String ringtoneTitle = null;
if (mValue != null) {
if (mValue.length() == 0)
ringtoneTitle = mContext.getString(R.string.silent);
if (ringtoneTitle == null && mExtraRingtones != null && mExtraRingtoneTitles != null) {
for (int i = 0; i < mExtraRingtones.length; i++) {
Uri uriExtra = uriFromRaw(mExtraRingtones[i].toString());
if (uriExtra.equals(Uri.parse(mValue))) {
ringtoneTitle = mExtraRingtoneTitles[i].toString();
break;
}
}
}
if (ringtoneTitle == null) {
Ringtone ringtone = RingtoneManager.getRingtone(mContext, Uri.parse(mValue));
String title = ringtone.getTitle(mContext);
if (title != null && title.length() > 0)
ringtoneTitle = title;
}
}
CharSequence summary = super.getSummary();
if (ringtoneTitle != null) {
if (summary != null)
return String.format(summary.toString(), ringtoneTitle);
else
return ringtoneTitle;
} else return summary;
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
final Map<String, Uri> sounds = new LinkedHashMap<String, Uri>();
if (mExtraRingtones != null) {
for (CharSequence extraRingtone : mExtraRingtones) {
Uri uri = uriFromRaw(extraRingtone.toString());
String title = getExtraRingtoneTitle(extraRingtone);
sounds.put(title, uri);
}
}
if (mShowDefault) {
Uri uriDefault = RingtoneManager.getDefaultUri(mRingtoneType);
if (uriDefault != null) {
Ringtone ringtoneDefault = RingtoneManager.getRingtone(mContext, uriDefault);
if (ringtoneDefault != null) {
sounds.put(ringtoneDefault.getTitle(mContext), uriDefault);
}
}
}
if (mShowSilent)
sounds.put(mContext.getString(R.string.silent), Uri.parse(""));
sounds.putAll(getSounds(RingtoneManager.TYPE_NOTIFICATION));
final String[] titleArray = sounds.keySet().toArray(new String[0]);
final Uri[] uriArray = sounds.values().toArray(new Uri[0]);
int index = mValue != null ? Arrays.asList(uriArray).indexOf(Uri.parse(mValue)) : -1;
builder.setSingleChoiceItems(titleArray, index, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (ringtone != null)
ringtone.stop();
String title = titleArray[which];
Uri uri = uriArray[which];
if (uri != null) {
if (uri.toString().length() > 0) {
ringtone = RingtoneManager.getRingtone(mContext, uri);
ringtone.play();
}
mValue = uri.toString();
} else mValue = null;
}
});
builder.setPositiveButton(R.string.ok, this);
builder.setNegativeButton(R.string.cancel, this);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (ringtone != null)
ringtone.stop();
if (positiveResult && callChangeListener(mValue)) {
persistString(mValue);
notifyChanged();
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if (restoreValue)
mValue = getPersistedString("");
else {
if (mExtraRingtones != null && defaultValue != null && defaultValue.toString().length() > 0) {
int index = Arrays.asList(mExtraRingtones).indexOf((CharSequence) defaultValue);
if (index >= 0)
mValue = uriFromRaw(defaultValue.toString()).toString();
else mValue = (String) defaultValue;
} else mValue = (String) defaultValue;
persistString(mValue);
}
}
}
res/values/attrs.xml
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<declare-styleable name="ExtraRingtonePreference">
<attr name="ringtoneType">
<!-- Ringtones. -->
<flag name="ringtone" value="1" />
<!-- Notification sounds. -->
<flag name="notification" value="2" />
<!-- Alarm sounds. -->
<flag name="alarm" value="4" />
<!-- All available ringtone sounds. -->
<flag name="all" value="7" />
</attr>
<attr name="showSilent" format="boolean"/>
<attr name="showDefault" format="boolean"/>
<attr name="extraRingtones" format="reference"/>
<attr name="extraRingtoneTitles" format="reference"/>
</declare-styleable>
</resources>
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="silent">Silent</string>
<string name="ok">OK</string>
<string name="cancel">Cancel</string>
<string name="ringtoneTitle">Ringtone</string>
<string name="ringtoneSummary">Ringtone: %s</string>
<string-array name="extraRingtones">
<item>deichkind_sone_musik</item>
<item>madonna_like_a_virgin</item>
</string-array>
<string-array name="extraRingtoneTitles">
<item>Sone Musik</item>
<item>Like A Virgin</item>
</string-array>
</resources>
res/raw
res
↳ raw
↳ deichkind_sone_musik.mp3
↳ madonna_like_a_virgin.mp3
res/xml/preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:auto="http://schemas.android.com/apk/res-auto">
<de.almisoft.test.ExtraRingtonePreference
android:key="ringtone"
android:title="@string/ringtoneTitle"
android:summary="@string/ringtoneSummary"
android:defaultValue="deichkind_sone_musik"
auto:ringtoneType="notification"
auto:showSilent="true"
auto:showDefault="true"
auto:extraRingtones="@array/extraRingtones"
auto:extraRingtoneTitles="@array/extraRingtoneTitles"/>
<!-- set android:defaultValue
to "deichkind_sone_musik" for your custom mp3
to "" for silent
to "content://settings/system/notification_sound" for system default ringtone -->
</PreferenceScreen>
So finally I looked into the source code of ListPreference and made the same with some modifcations. As I can't use com.android.internal.R.styleable.ListPreference I had to create my own styleable in attrs.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ListPreference">
<attr name="entries" format="string"></attr>
<attr name="entryValues" format="string"></attr>
</declare-styleable>
<declare-styleable name="Preference">
<attr name="summary" format="string"></attr>
</declare-styleable>
</resources>
and then import it in my preferences.xml file like this:
xmlns:foo="http://schemas.android.com/apk/res/com.abe.abemoto"
and uses it :
<com.abe.abemoto.preference.CustomSoundListPreference
android:defaultValue="@string/pref_alert_ring_value_1"
android:key="@string/pref_alert_sound_choice_for_notif_key"
android:title="Sonnerie de notification"
foo:entries="@array/pref_alert_ring_entries"
foo:entryValues="@array/pref_alert_ring_values"
foo:summary="Choisissez la sonnerie pour les notifications" />
In my class CustomSoundListPreference I modified the method onPrepareDialogBuilder to play my sound on item clicked.
@Override
protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder);
mMediaPlayer = new MediaPlayer();
if (mEntries == null || mEntryValues == null) {
throw new IllegalStateException(
"ListPreference requires an entries array and an entryValues array.");
}
mClickedDialogEntryIndex = getValueIndex();
builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mClickedDialogEntryIndex = which;
String value = mEntryValues[which].toString();
Resources res = getContext().getResources();
int resId = res.getIdentifier(value, "raw",
getContext().getPackageName());
Uri uri = Uri.parse(String.format(getContext()
.getString(R.string.resource_sound),
getContext().getPackageName(), resId));
Log.d(TAG, "uri sound = " + uri);
try {
mMediaPlayer.reset();
mMediaPlayer.setDataSource(getContext(), uri);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
builder.setPositiveButton("Ok", this);
builder.setNegativeButton("Annuler", this);
}
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