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 17 package com.android.settings; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.res.TypedArray; 22 import android.media.AudioAttributes; 23 import android.media.RingtoneManager; 24 import android.net.Uri; 25 import android.os.UserHandle; 26 import android.provider.Settings.System; 27 import android.support.v7.preference.Preference; 28 import android.support.v7.preference.PreferenceManager; 29 import android.text.TextUtils; 30 import android.util.AttributeSet; 31 32 /** 33 * A {@link Preference} that allows the user to choose a ringtone from those on the device. 34 * The chosen ringtone's URI will be persisted as a string. 35 * <p> 36 * If the user chooses the "Default" item, the saved string will be one of 37 * {@link System#DEFAULT_RINGTONE_URI}, 38 * {@link System#DEFAULT_NOTIFICATION_URI}, or 39 * {@link System#DEFAULT_ALARM_ALERT_URI}. If the user chooses the "Silent" 40 * item, the saved string will be an empty string. 41 * 42 * @attr ref android.R.styleable#RingtonePreference_ringtoneType 43 * @attr ref android.R.styleable#RingtonePreference_showDefault 44 * @attr ref android.R.styleable#RingtonePreference_showSilent 45 * 46 * Based of frameworks/base/core/java/android/preference/RingtonePreference.java 47 * but extends android.support.v7.preference.Preference instead. 48 */ 49 public class RingtonePreference extends Preference { 50 51 private static final String TAG = "RingtonePreference"; 52 53 private int mRingtoneType; 54 private boolean mShowDefault; 55 private boolean mShowSilent; 56 57 private int mRequestCode; 58 protected int mUserId; 59 protected Context mUserContext; 60 RingtonePreference(Context context, AttributeSet attrs)61 public RingtonePreference(Context context, AttributeSet attrs) { 62 super(context, attrs); 63 64 final TypedArray a = context.obtainStyledAttributes(attrs, 65 com.android.internal.R.styleable.RingtonePreference, 0, 0); 66 mRingtoneType = a.getInt(com.android.internal.R.styleable.RingtonePreference_ringtoneType, 67 RingtoneManager.TYPE_RINGTONE); 68 mShowDefault = a.getBoolean(com.android.internal.R.styleable.RingtonePreference_showDefault, 69 true); 70 mShowSilent = a.getBoolean(com.android.internal.R.styleable.RingtonePreference_showSilent, 71 true); 72 setIntent(new Intent(RingtoneManager.ACTION_RINGTONE_PICKER)); 73 setUserId(UserHandle.myUserId()); 74 a.recycle(); 75 } 76 setUserId(int userId)77 public void setUserId(int userId) { 78 mUserId = userId; 79 mUserContext = Utils.createPackageContextAsUser(getContext(), mUserId); 80 } 81 getUserId()82 public int getUserId() { 83 return mUserId; 84 } 85 86 /** 87 * Returns the sound type(s) that are shown in the picker. 88 * 89 * @return The sound type(s) that are shown in the picker. 90 * @see #setRingtoneType(int) 91 */ getRingtoneType()92 public int getRingtoneType() { 93 return mRingtoneType; 94 } 95 96 /** 97 * Sets the sound type(s) that are shown in the picker. 98 * 99 * @param type The sound type(s) that are shown in the picker. 100 * @see RingtoneManager#EXTRA_RINGTONE_TYPE 101 */ setRingtoneType(int type)102 public void setRingtoneType(int type) { 103 mRingtoneType = type; 104 } 105 106 /** 107 * Returns whether to a show an item for the default sound/ringtone. 108 * 109 * @return Whether to show an item for the default sound/ringtone. 110 */ getShowDefault()111 public boolean getShowDefault() { 112 return mShowDefault; 113 } 114 115 /** 116 * Sets whether to show an item for the default sound/ringtone. The default 117 * to use will be deduced from the sound type(s) being shown. 118 * 119 * @param showDefault Whether to show the default or not. 120 * @see RingtoneManager#EXTRA_RINGTONE_SHOW_DEFAULT 121 */ setShowDefault(boolean showDefault)122 public void setShowDefault(boolean showDefault) { 123 mShowDefault = showDefault; 124 } 125 126 /** 127 * Returns whether to a show an item for 'Silent'. 128 * 129 * @return Whether to show an item for 'Silent'. 130 */ getShowSilent()131 public boolean getShowSilent() { 132 return mShowSilent; 133 } 134 135 /** 136 * Sets whether to show an item for 'Silent'. 137 * 138 * @param showSilent Whether to show 'Silent'. 139 * @see RingtoneManager#EXTRA_RINGTONE_SHOW_SILENT 140 */ setShowSilent(boolean showSilent)141 public void setShowSilent(boolean showSilent) { 142 mShowSilent = showSilent; 143 } 144 getRequestCode()145 public int getRequestCode() { 146 return mRequestCode; 147 } 148 149 /** 150 * Prepares the intent to launch the ringtone picker. This can be modified 151 * to adjust the parameters of the ringtone picker. 152 * 153 * @param ringtonePickerIntent The ringtone picker intent that can be 154 * modified by putting extras. 155 */ onPrepareRingtonePickerIntent(Intent ringtonePickerIntent)156 public void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) { 157 158 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, 159 onRestoreRingtone()); 160 161 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, mShowDefault); 162 if (mShowDefault) { 163 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, 164 RingtoneManager.getDefaultUri(getRingtoneType())); 165 } 166 167 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, mShowSilent); 168 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, mRingtoneType); 169 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, getTitle()); 170 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_AUDIO_ATTRIBUTES_FLAGS, 171 AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY); 172 } 173 174 /** 175 * Called when a ringtone is chosen. 176 * <p> 177 * By default, this saves the ringtone URI to the persistent storage as a 178 * string. 179 * 180 * @param ringtoneUri The chosen ringtone's {@link Uri}. Can be null. 181 */ onSaveRingtone(Uri ringtoneUri)182 protected void onSaveRingtone(Uri ringtoneUri) { 183 persistString(ringtoneUri != null ? ringtoneUri.toString() : ""); 184 } 185 186 /** 187 * Called when the chooser is about to be shown and the current ringtone 188 * should be marked. Can return null to not mark any ringtone. 189 * <p> 190 * By default, this restores the previous ringtone URI from the persistent 191 * storage. 192 * 193 * @return The ringtone to be marked as the current ringtone. 194 */ onRestoreRingtone()195 protected Uri onRestoreRingtone() { 196 final String uriString = getPersistedString(null); 197 return !TextUtils.isEmpty(uriString) ? Uri.parse(uriString) : null; 198 } 199 200 @Override onGetDefaultValue(TypedArray a, int index)201 protected Object onGetDefaultValue(TypedArray a, int index) { 202 return a.getString(index); 203 } 204 205 @Override onSetInitialValue(boolean restorePersistedValue, Object defaultValueObj)206 protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValueObj) { 207 String defaultValue = (String) defaultValueObj; 208 209 /* 210 * This method is normally to make sure the internal state and UI 211 * matches either the persisted value or the default value. Since we 212 * don't show the current value in the UI (until the dialog is opened) 213 * and we don't keep local state, if we are restoring the persisted 214 * value we don't need to do anything. 215 */ 216 if (restorePersistedValue) { 217 return; 218 } 219 220 // If we are setting to the default value, we should persist it. 221 if (!TextUtils.isEmpty(defaultValue)) { 222 onSaveRingtone(Uri.parse(defaultValue)); 223 } 224 } onAttachedToHierarchy(PreferenceManager preferenceManager)225 protected void onAttachedToHierarchy(PreferenceManager preferenceManager) { 226 super.onAttachedToHierarchy(preferenceManager); 227 } 228 onActivityResult(int requestCode, int resultCode, Intent data)229 public boolean onActivityResult(int requestCode, int resultCode, Intent data) { 230 if (data != null) { 231 Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); 232 233 if (callChangeListener(uri != null ? uri.toString() : "")) { 234 onSaveRingtone(uri); 235 } 236 } 237 238 return true; 239 } 240 241 } 242