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