1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.preference; 18 19import android.content.Context; 20import android.content.Intent; 21import android.content.res.TypedArray; 22import android.media.RingtoneManager; 23import android.net.Uri; 24import android.provider.Settings.System; 25import android.text.TextUtils; 26import android.util.AttributeSet; 27import android.util.Log; 28 29/** 30 * A {@link Preference} that allows the user to choose a ringtone from those on the device. 31 * The chosen ringtone's URI will be persisted as a string. 32 * <p> 33 * If the user chooses the "Default" item, the saved string will be one of 34 * {@link System#DEFAULT_RINGTONE_URI}, 35 * {@link System#DEFAULT_NOTIFICATION_URI}, or 36 * {@link System#DEFAULT_ALARM_ALERT_URI}. If the user chooses the "Silent" 37 * item, the saved string will be an empty string. 38 * 39 * @attr ref android.R.styleable#RingtonePreference_ringtoneType 40 * @attr ref android.R.styleable#RingtonePreference_showDefault 41 * @attr ref android.R.styleable#RingtonePreference_showSilent 42 */ 43public class RingtonePreference extends Preference implements 44 PreferenceManager.OnActivityResultListener { 45 46 private static final String TAG = "RingtonePreference"; 47 48 private int mRingtoneType; 49 private boolean mShowDefault; 50 private boolean mShowSilent; 51 52 private int mRequestCode; 53 54 public RingtonePreference(Context context, AttributeSet attrs, int defStyle) { 55 super(context, attrs, defStyle); 56 57 TypedArray a = context.obtainStyledAttributes(attrs, 58 com.android.internal.R.styleable.RingtonePreference, defStyle, 0); 59 mRingtoneType = a.getInt(com.android.internal.R.styleable.RingtonePreference_ringtoneType, 60 RingtoneManager.TYPE_RINGTONE); 61 mShowDefault = a.getBoolean(com.android.internal.R.styleable.RingtonePreference_showDefault, 62 true); 63 mShowSilent = a.getBoolean(com.android.internal.R.styleable.RingtonePreference_showSilent, 64 true); 65 a.recycle(); 66 } 67 68 public RingtonePreference(Context context, AttributeSet attrs) { 69 this(context, attrs, com.android.internal.R.attr.ringtonePreferenceStyle); 70 } 71 72 public RingtonePreference(Context context) { 73 this(context, null); 74 } 75 76 /** 77 * Returns the sound type(s) that are shown in the picker. 78 * 79 * @return The sound type(s) that are shown in the picker. 80 * @see #setRingtoneType(int) 81 */ 82 public int getRingtoneType() { 83 return mRingtoneType; 84 } 85 86 /** 87 * Sets the sound type(s) that are shown in the picker. 88 * 89 * @param type The sound type(s) that are shown in the picker. 90 * @see RingtoneManager#EXTRA_RINGTONE_TYPE 91 */ 92 public void setRingtoneType(int type) { 93 mRingtoneType = type; 94 } 95 96 /** 97 * Returns whether to a show an item for the default sound/ringtone. 98 * 99 * @return Whether to show an item for the default sound/ringtone. 100 */ 101 public boolean getShowDefault() { 102 return mShowDefault; 103 } 104 105 /** 106 * Sets whether to show an item for the default sound/ringtone. The default 107 * to use will be deduced from the sound type(s) being shown. 108 * 109 * @param showDefault Whether to show the default or not. 110 * @see RingtoneManager#EXTRA_RINGTONE_SHOW_DEFAULT 111 */ 112 public void setShowDefault(boolean showDefault) { 113 mShowDefault = showDefault; 114 } 115 116 /** 117 * Returns whether to a show an item for 'Silent'. 118 * 119 * @return Whether to show an item for 'Silent'. 120 */ 121 public boolean getShowSilent() { 122 return mShowSilent; 123 } 124 125 /** 126 * Sets whether to show an item for 'Silent'. 127 * 128 * @param showSilent Whether to show 'Silent'. 129 * @see RingtoneManager#EXTRA_RINGTONE_SHOW_SILENT 130 */ 131 public void setShowSilent(boolean showSilent) { 132 mShowSilent = showSilent; 133 } 134 135 @Override 136 protected void onClick() { 137 // Launch the ringtone picker 138 Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); 139 onPrepareRingtonePickerIntent(intent); 140 getPreferenceManager().getActivity().startActivityForResult(intent, mRequestCode); 141 } 142 143 /** 144 * Prepares the intent to launch the ringtone picker. This can be modified 145 * to adjust the parameters of the ringtone picker. 146 * 147 * @param ringtonePickerIntent The ringtone picker intent that can be 148 * modified by putting extras. 149 */ 150 protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) { 151 152 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, 153 onRestoreRingtone()); 154 155 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, mShowDefault); 156 if (mShowDefault) { 157 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, 158 RingtoneManager.getDefaultUri(getRingtoneType())); 159 } 160 161 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, mShowSilent); 162 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, mRingtoneType); 163 } 164 165 /** 166 * Called when a ringtone is chosen. 167 * <p> 168 * By default, this saves the ringtone URI to the persistent storage as a 169 * string. 170 * 171 * @param ringtoneUri The chosen ringtone's {@link Uri}. Can be null. 172 */ 173 protected void onSaveRingtone(Uri ringtoneUri) { 174 persistString(ringtoneUri != null ? ringtoneUri.toString() : ""); 175 } 176 177 /** 178 * Called when the chooser is about to be shown and the current ringtone 179 * should be marked. Can return null to not mark any ringtone. 180 * <p> 181 * By default, this restores the previous ringtone URI from the persistent 182 * storage. 183 * 184 * @return The ringtone to be marked as the current ringtone. 185 */ 186 protected Uri onRestoreRingtone() { 187 final String uriString = getPersistedString(null); 188 return !TextUtils.isEmpty(uriString) ? Uri.parse(uriString) : null; 189 } 190 191 @Override 192 protected Object onGetDefaultValue(TypedArray a, int index) { 193 return a.getString(index); 194 } 195 196 @Override 197 protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValueObj) { 198 String defaultValue = (String) defaultValueObj; 199 200 /* 201 * This method is normally to make sure the internal state and UI 202 * matches either the persisted value or the default value. Since we 203 * don't show the current value in the UI (until the dialog is opened) 204 * and we don't keep local state, if we are restoring the persisted 205 * value we don't need to do anything. 206 */ 207 if (restorePersistedValue) { 208 return; 209 } 210 211 // If we are setting to the default value, we should persist it. 212 if (!TextUtils.isEmpty(defaultValue)) { 213 onSaveRingtone(Uri.parse(defaultValue)); 214 } 215 } 216 217 @Override 218 protected void onAttachedToHierarchy(PreferenceManager preferenceManager) { 219 super.onAttachedToHierarchy(preferenceManager); 220 221 preferenceManager.registerOnActivityResultListener(this); 222 mRequestCode = preferenceManager.getNextRequestCode(); 223 } 224 225 public boolean onActivityResult(int requestCode, int resultCode, Intent data) { 226 227 if (requestCode == mRequestCode) { 228 229 if (data != null) { 230 Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); 231 232 if (callChangeListener(uri != null ? uri.toString() : "")) { 233 onSaveRingtone(uri); 234 } 235 } 236 237 return true; 238 } 239 240 return false; 241 } 242 243} 244