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.
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);
}
Here is the full code for a custom ListPreference just like a ringtone preference:
import java.io.IOException;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.ListPreference;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
public class CustomListPreference extends ListPreference{
private MediaPlayer mMediaPlayer;
private Context mContext;
CharSequence[] mEntries;
CharSequence[] mEntryValues;
private int mClickedDialogEntryIndex;
private String mValue;
public CustomListPreference(Context context) {
super(context);
mContext = context;
}
/**
* Sets the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
*
* @param value The value to set for the key.
*/
public void setValue(String value) {
mValue = value;
persistString(value);
}
/**
* Sets the value to the given index from the entry values.
*
* @param index The index of the value to set.
*/
public void setValueIndex(int index) {
if (mEntryValues != null) {
setValue(mEntryValues[index].toString());
}
}
/**
* Returns the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
*
* @return The value of the key.
*/
public String getValue() {
return mValue;
}
/**
* Returns the entry corresponding to the current value.
*
* @return The entry corresponding to the current value, or null.
*/
public CharSequence getEntry() {
int index = getValueIndex();
return index >= 0 && mEntries != null ? mEntries[index] : null;
}
public int findIndexOfValue(String value) {
if (value != null && mEntryValues != null) {
for (int i = mEntryValues.length - 1; i >= 0; i--) {
if (mEntryValues[i].equals(value)) {
return i;
}
}
}
return -1;
}
private int getValueIndex() {
return findIndexOfValue(mValue);
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder);
mMediaPlayer = new MediaPlayer();
mEntries = getEntries();
mEntryValues = getEntryValues();
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();
String path = findPathFromName(value);
try {
playSong(path);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
builder.setPositiveButton("Ok", this);
builder.setNegativeButton("Cancel", this);
}
private void playSong(String path) throws IllegalArgumentException,
IllegalStateException, IOException {
Log.d("ringtone", "playSong :: " + path);
mMediaPlayer.reset();
mMediaPlayer.setDataSource(path);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
// mMediaPlayer.setLooping(true);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
public String findPathFromName(String name) {
Cursor mCursor = getContext().getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null,
MediaStore.Audio.Media.TITLE + "='" + name + "'", null, null );
String path = "";
if(mCursor.moveToFirst()){
path = mCursor.getString(mCursor.getColumnIndex(MediaStore.Audio.Media.DATA));
}
mCursor.close();
mCursor = null;
return path;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
setValue(myState.value);
}
private static class SavedState extends BaseSavedState {
String value;
public SavedState(Parcel source) {
super(source);
value = source.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(value);
}
public SavedState(Parcelable superState) {
super(superState);
}
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
String value = mEntryValues[mClickedDialogEntryIndex].toString();
if (callChangeListener(value)) {
setValue(value);
}
}
mMediaPlayer.stop();
mMediaPlayer.release();
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
final SavedState myState = new SavedState(superState);
myState.value = getValue();
return myState;
}
}
Hope this will be helpful to someone.
when making a ringtone preference customization i prefer that the ringtone only play for short while, sort of like a sample sounds. user does not need to hear the entire sound play if they are just choosing a sound from a list. Here is how i achieve this:
first create a service that will play the ringtone (well use ringtone manager to play the sound instead of media player as its handling the cancelling for us):
public class PlayRingtoneService extends Service { static Ringtone r; private Handler handler;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//activating alarm sound
if (r != null)
r.stop();
String filePath = intent.getStringExtra("uri");
r = RingtoneManager.getRingtone(this, Uri.parse(filePath));
r.play();
handler.removeCallbacksAndMessages(null);
handler.postDelayed(new Runnable() {
@Override
public void run() {
if(r!=null)
r.stop();
}
},6000L); //stop sound in 6 seconds
return super.onStartCommand(intent, flags, startId);
}
void setThreadPriority(int priority) {
try {
Process.setThreadPriority(priority);
} catch (Exception e) {
Timber.e(e);
}
}
@Override
public void onCreate() {
super.onCreate();
handler =new Handler();
setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
}
@Override
public void onDestroy() {
if (r != null)
r.stop();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
also update the manifest with the service:
<service android:name=".services.PlayRingtoneService" />
then using the solutions above but modified you can create a list preference that behaves just like a ringtone preference:
public class CustomRingtoneListPreference extends ListPreference {
CharSequence[] mEntries;
CharSequence[] mEntryValues;
private int mClickedDialogEntryIndex;
private String mValue;
public CustomRingtoneListPreference(Context context) {
super(context);
}
public CustomRingtoneListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* Returns the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
*
* @return The value of the key.
*/
public String getValue() {
return mValue;
}
/**
* Sets the value of the key. This should be one of the entries in
* {@link #getEntryValues()}.
*
* @param value The value to set for the key.
*/
public void setValue(String value) {
mValue = value;
persistString(value);
}
/**
* Returns the entry corresponding to the current value.
*
* @return The entry corresponding to the current value, or null.
*/
public CharSequence getEntry() {
int index = getValueIndex();
return index >= 0 && mEntries != null ? mEntries[index] : null;
}
public int findIndexOfValue(String value) {
if (value != null && mEntryValues != null) {
for (int i = mEntryValues.length - 1; i >= 0; i--) {
if (mEntryValues[i].equals(value)) {
return i;
}
}
}
return -1;
}
private int getValueIndex() {
return findIndexOfValue(mValue);
}
/**
* Sets the value to the given index from the entry values.
*
* @param index The index of the value to set.
*/
public void setValueIndex(int index) {
if (mEntryValues != null) {
setValue(mEntryValues[index].toString());
}
}
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
mEntries = getEntries();
mEntryValues = getEntryValues();
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();
playSong(value);
}
});
builder.setPositiveButton("Ok", this);
builder.setNegativeButton("Cancel", this);
}
private void playSong(String path) {
Intent i = new Intent(getContext(), PlayRingtoneService.class);
i.putExtra("uri", path);
getContext().startService(i);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
setValue(myState.value);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
String value = mEntryValues[mClickedDialogEntryIndex].toString();
if (callChangeListener(value)) {
setValue(value);
}
}
Intent i = new Intent(getContext(), PlayRingtoneService.class);
getContext().stopService(i);
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
final SavedState myState = new SavedState(superState);
myState.value = getValue();
return myState;
}
private static class SavedState extends BaseSavedState {
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
String value;
public SavedState(Parcel source) {
super(source);
value = source.readString();
}
public SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(value);
}
}
}
now in your xml use it like this:
<mypackage.blah.blah.CustomRingtoneListPreference
android:key="myRingtone"
android:title="my title"
android:summary="ringtone chosen %s"
android:defaultValue="0"
android:dependency="whatever you have"
/>
now to actually load up the values into the list we create a utils method that can get all internal and external media and put it into our model class called songs defined like this:
public class Song {
private long id;
private Uri filePath;
private boolean externalPath;
/**
* Creates a new Song, with specified `songID` and `filePath`.
*
* @note It's a unique Android identifier for a media file
* anywhere on the system.
*/
public Song(long id, String title, String artist, Uri fileUri, boolean externalPath) {
this.id = id;
this.title = title;
this.artist = artist;
this.filePath = fileUri;
this.externalPath = externalPath;
}
/**
* Identifier for the song on the Android system.
* (so we can locate the file anywhere)
*/
public long getId() {
return id;
}
public Uri getFilePath() {
return filePath;
}
public Song setFilePath(Uri filePath) {
this.filePath = filePath;
return this;
}
private String title = "";
private String artist = "";
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public boolean isExternalPath() {
return externalPath;
}
public Song setIsExternalPath(boolean externalPath) {
this.externalPath = externalPath;
return this;
}
}
Now in your Util class or just a static method if you want you do make this class which will query the media store for all audio files:
public static List getAllExternalAudioSongs(Context c) { List songList = new ArrayList<>(); ContentResolver contentResolver = c.getContentResolver();
List<Uri> contentUriLists = new ArrayList<>();
contentUriLists.add(MediaStore.Audio.Media.INTERNAL_CONTENT_URI);
contentUriLists.add(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
String selection= MediaStore.Audio.Media.DURATION + ">= 3000";
boolean externalPath = false;
for (Uri uri : contentUriLists) {
Cursor cursor = contentResolver.query(uri, null, selection, null, android.provider.MediaStore.Audio.Media.TITLE+ " ASC");
if (cursor == null) {
// query failed, handle error.
} else if (!cursor.moveToFirst()) {
// no media on the device
} else {
int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
int artistColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
do {
long id = cursor.getLong(idColumn);
String title = cursor.getString(titleColumn);
String artist = cursor.getString(artistColumn);
Uri contentUri = ContentUris.withAppendedId(
uri, id);
Song song = new Song(id, title, artist, contentUri, externalPath);
songList.add(song);
} while (cursor.moveToNext());
externalPath=true;
}
}
return songList;
}
note: the externalPath is just if you want to differentiate internal from external audio files.
Finally, in onCreate of preferenceActivity (or fragment) you can do this:
private void setRingtoneList() {
ListPreference listPreferenceCategory = (ListPreference) findPreference("myRingtone");
if (listPreferenceCategory != null) {
List<Song> songList = Utils.getAllExternalAudioSongs(getApplicationContext());
CharSequence entries[] = new String[songList.size()];
CharSequence entryValues[] = new String[songList.size()];
int i = 0;
for (Song song : songList) {
entries[i] = song.getTitle();
entryValues[i] = song.getFilePath().toString();
i++;
}
listPreferenceCategory.setEntries(entries);
listPreferenceCategory.setEntryValues(entryValues);
}
}
note: you'll need runtime permissions for external storage. and also to update the summary youll have to do that in the preference activity i believe. anyway this gives a good idea how to play sample audio instead of entire audio file.
© 2022 - 2024 — McMap. All rights reserved.