package mobi.boilr.boilr.preference; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.database.Cursor; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.RingtoneManager; import android.preference.ListPreference; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.util.AttributeSet; import mobi.boilr.boilr.R; import mobi.boilr.boilr.utils.Conversions; import mobi.boilr.boilr.utils.Log; import mobi.boilr.boilr.views.fragments.AlarmPreferencesFragment; import mobi.boilr.boilr.views.fragments.SettingsFragment; /** * RingtonePreference which adjusts to the current theme and has an app default * ringtone (instead of system default). * * Copyright (C) 2013 Trinitrotoluol (licensed under CC BY-SA 3.0) * (C) 2014 Martin Pfeffer (licensed under CC BY-SA 3.0) * https://stackoverflow.com/questions/16589467/ringtonepreference-theme/16702655 * (C) 2015 David Ludovino <[email protected]>, Boilr (modifications licensed under GPLv3) */ public class ThemableRingtonePreference extends ListPreference { private MediaPlayer mMediaPlayer; private int mClickedDialogEntryIndex, mRingtoneType = 4; private boolean mCurrentShowDefault, mShowDefault; private String mAppRingtone; private SharedPreferences mSharedPrefs; /* Pattern to match something like: * content://media/internal/audio/media/38 */ private Pattern p = Pattern.compile("[a-z:/]+\\d+"); /** * After the constructor call setRingtoneType(int) to fill ringtone's list. */ public ThemableRingtonePreference(Context context, AttributeSet attrs) { super(context, attrs); if(attrs != null) { Theme t = context.getTheme(); TypedArray a = t.obtainStyledAttributes(attrs, R.styleable.ThemableRingtonePreference, 0, 0); try { mCurrentShowDefault = mShowDefault = a.getBoolean(R.styleable.ThemableRingtonePreference_showDefault, false); } finally { a.recycle(); } } mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); } /** * 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. */ @Override public void setValue(String value) { super.setValue(value); setSummary(getEntry()); } @Override protected void onPrepareDialogBuilder(Builder builder) { super.onPrepareDialogBuilder(builder); mMediaPlayer = new MediaPlayer(); CharSequence[] entries = getEntries(); CharSequence[] entryValues = getEntryValues(); if(entries == null || entryValues == null) { throw new IllegalStateException("ListPreference requires an entries array and an entryValues array."); } mClickedDialogEntryIndex = findIndexOfValue(getValue()); builder.setSingleChoiceItems(entries, mClickedDialogEntryIndex, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mClickedDialogEntryIndex = which; String value = getEntryValues()[which].toString(); if(value.equals(AlarmPreferencesFragment.DEFAULT)) value = mAppRingtone; try { playTone(value); } catch(Exception e) { Log.e("Could not play ringtone. " + e); } } }); builder.setPositiveButton(getContext().getString(R.string.ok), this); builder.setNegativeButton(getContext().getString(R.string.cancel), this); } private void playTone(String path) throws IllegalArgumentException, IllegalStateException, IOException { mMediaPlayer.reset(); mMediaPlayer.setDataSource(path); mMediaPlayer.setAudioStreamType(AudioManager.STREAM_RING); // mMediaPlayer.setLooping(true); mMediaPlayer.prepare(); mMediaPlayer.start(); } @Override protected void onDialogClosed(boolean positiveResult) { super.onDialogClosed(positiveResult); CharSequence[] entryValues = getEntryValues(); if(positiveResult && mClickedDialogEntryIndex >= 0 && entryValues != null) { String value = entryValues[mClickedDialogEntryIndex].toString(); if(callChangeListener(value)) { setValue(value); } } mMediaPlayer.stop(); mMediaPlayer.release(); } private int getAlertInt(String alertType) { return Integer.parseInt(alertType.equals(AlarmPreferencesFragment.DEFAULT) ? AlarmPreferencesFragment.getDefaultAlertType(mSharedPrefs, getContext()) : alertType); } public void setRingtoneType(String alertType) { mRingtoneType = getAlertInt(alertType); RingtoneManager ringtoneManager = new RingtoneManager(getContext()); mCurrentShowDefault = mShowDefault && alertType.equals(AlarmPreferencesFragment.DEFAULT) ? true : false; ringtoneManager.setType(mRingtoneType); final Cursor ringtones = ringtoneManager.getCursor(); List<String> entries = new ArrayList<String>(); List<String> entryValues = new ArrayList<String>(); if(mCurrentShowDefault) { mAppRingtone = mSharedPrefs.getString( SettingsFragment.PREF_KEY_DEFAULT_ALERT_SOUND, Conversions.getSystemRingtone(mRingtoneType, getContext())); entries.add(getContext().getString(R.string.default_value, Conversions.ringtoneUriToName(mAppRingtone, getContext()))); entryValues.add(AlarmPreferencesFragment.DEFAULT); } // Silent entries.add(getContext().getString(R.string.silent)); entryValues.add(""); String value; int id; Matcher m; for(ringtones.moveToFirst(); !ringtones.isAfterLast(); ringtones.moveToNext()) { entries.add(ringtones.getString(RingtoneManager.TITLE_COLUMN_INDEX)); value = ringtones.getString(RingtoneManager.URI_COLUMN_INDEX); m = p.matcher(value); if(!m.matches()) { id = ringtones.getInt(ringtones.getColumnIndex(MediaStore.MediaColumns._ID)); value += "/" + id; } entryValues.add(value); } setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()])); setEntries(entries.toArray(new CharSequence[entries.size()])); } public void setDefaultValue() { if(mCurrentShowDefault) { setValue((String) getEntryValues()[0]); } else { setValue(Conversions.getSystemRingtone(mRingtoneType, getContext())); } } }