ListPreference.java revision 94c02a1a1a6d7e6900e5a459e9cc699b9510e5a2
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.app.AlertDialog.Builder; 20import android.content.Context; 21import android.content.DialogInterface; 22import android.content.res.TypedArray; 23import android.os.Parcel; 24import android.os.Parcelable; 25import android.text.TextUtils; 26import android.util.AttributeSet; 27 28/** 29 * A {@link Preference} that displays a list of entries as 30 * a dialog. 31 * <p> 32 * This preference will store a string into the SharedPreferences. This string will be the value 33 * from the {@link #setEntryValues(CharSequence[])} array. 34 * 35 * @attr ref android.R.styleable#ListPreference_entries 36 * @attr ref android.R.styleable#ListPreference_entryValues 37 */ 38public class ListPreference extends DialogPreference { 39 private CharSequence[] mEntries; 40 private CharSequence[] mEntryValues; 41 private String mValue; 42 private String mSummary; 43 private int mClickedDialogEntryIndex; 44 private boolean mValueSet; 45 46 public ListPreference(Context context, AttributeSet attrs) { 47 super(context, attrs); 48 49 TypedArray a = context.obtainStyledAttributes(attrs, 50 com.android.internal.R.styleable.ListPreference, 0, 0); 51 mEntries = a.getTextArray(com.android.internal.R.styleable.ListPreference_entries); 52 mEntryValues = a.getTextArray(com.android.internal.R.styleable.ListPreference_entryValues); 53 a.recycle(); 54 55 /* Retrieve the Preference summary attribute since it's private 56 * in the Preference class. 57 */ 58 a = context.obtainStyledAttributes(attrs, 59 com.android.internal.R.styleable.Preference, 0, 0); 60 mSummary = a.getString(com.android.internal.R.styleable.Preference_summary); 61 a.recycle(); 62 } 63 64 public ListPreference(Context context) { 65 this(context, null); 66 } 67 68 /** 69 * Sets the human-readable entries to be shown in the list. This will be 70 * shown in subsequent dialogs. 71 * <p> 72 * Each entry must have a corresponding index in 73 * {@link #setEntryValues(CharSequence[])}. 74 * 75 * @param entries The entries. 76 * @see #setEntryValues(CharSequence[]) 77 */ 78 public void setEntries(CharSequence[] entries) { 79 mEntries = entries; 80 } 81 82 /** 83 * @see #setEntries(CharSequence[]) 84 * @param entriesResId The entries array as a resource. 85 */ 86 public void setEntries(int entriesResId) { 87 setEntries(getContext().getResources().getTextArray(entriesResId)); 88 } 89 90 /** 91 * The list of entries to be shown in the list in subsequent dialogs. 92 * 93 * @return The list as an array. 94 */ 95 public CharSequence[] getEntries() { 96 return mEntries; 97 } 98 99 /** 100 * The array to find the value to save for a preference when an entry from 101 * entries is selected. If a user clicks on the second item in entries, the 102 * second item in this array will be saved to the preference. 103 * 104 * @param entryValues The array to be used as values to save for the preference. 105 */ 106 public void setEntryValues(CharSequence[] entryValues) { 107 mEntryValues = entryValues; 108 } 109 110 /** 111 * @see #setEntryValues(CharSequence[]) 112 * @param entryValuesResId The entry values array as a resource. 113 */ 114 public void setEntryValues(int entryValuesResId) { 115 setEntryValues(getContext().getResources().getTextArray(entryValuesResId)); 116 } 117 118 /** 119 * Returns the array of values to be saved for the preference. 120 * 121 * @return The array of values. 122 */ 123 public CharSequence[] getEntryValues() { 124 return mEntryValues; 125 } 126 127 /** 128 * Sets the value of the key. This should be one of the entries in 129 * {@link #getEntryValues()}. 130 * 131 * @param value The value to set for the key. 132 */ 133 public void setValue(String value) { 134 // Always persist/notify the first time. 135 final boolean changed = !TextUtils.equals(mValue, value); 136 if (changed || !mValueSet) { 137 mValue = value; 138 mValueSet = true; 139 persistString(value); 140 if (changed) { 141 notifyChanged(); 142 } 143 } 144 } 145 146 /** 147 * Returns the summary of this ListPreference. If the summary 148 * has a {@linkplain java.lang.String#format String formatting} 149 * marker in it (i.e. "%s" or "%1$s"), then the current entry 150 * value will be substituted in its place. 151 * 152 * @return the summary with appropriate string substitution 153 */ 154 @Override 155 public CharSequence getSummary() { 156 final CharSequence entry = getEntry(); 157 if (mSummary == null || entry == null) { 158 return super.getSummary(); 159 } else { 160 return String.format(mSummary, entry); 161 } 162 } 163 164 /** 165 * Sets the summary for this Preference with a CharSequence. 166 * If the summary has a 167 * {@linkplain java.lang.String#format String formatting} 168 * marker in it (i.e. "%s" or "%1$s"), then the current entry 169 * value will be substituted in its place when it's retrieved. 170 * 171 * @param summary The summary for the preference. 172 */ 173 @Override 174 public void setSummary(CharSequence summary) { 175 super.setSummary(summary); 176 if (summary == null && mSummary != null) { 177 mSummary = null; 178 } else if (summary != null && !summary.equals(mSummary)) { 179 mSummary = summary.toString(); 180 } 181 } 182 183 /** 184 * Sets the value to the given index from the entry values. 185 * 186 * @param index The index of the value to set. 187 */ 188 public void setValueIndex(int index) { 189 if (mEntryValues != null) { 190 setValue(mEntryValues[index].toString()); 191 } 192 } 193 194 /** 195 * Returns the value of the key. This should be one of the entries in 196 * {@link #getEntryValues()}. 197 * 198 * @return The value of the key. 199 */ 200 public String getValue() { 201 return mValue; 202 } 203 204 /** 205 * Returns the entry corresponding to the current value. 206 * 207 * @return The entry corresponding to the current value, or null. 208 */ 209 public CharSequence getEntry() { 210 int index = getValueIndex(); 211 return index >= 0 && mEntries != null ? mEntries[index] : null; 212 } 213 214 /** 215 * Returns the index of the given value (in the entry values array). 216 * 217 * @param value The value whose index should be returned. 218 * @return The index of the value, or -1 if not found. 219 */ 220 public int findIndexOfValue(String value) { 221 if (value != null && mEntryValues != null) { 222 for (int i = mEntryValues.length - 1; i >= 0; i--) { 223 if (mEntryValues[i].equals(value)) { 224 return i; 225 } 226 } 227 } 228 return -1; 229 } 230 231 private int getValueIndex() { 232 return findIndexOfValue(mValue); 233 } 234 235 @Override 236 protected void onPrepareDialogBuilder(Builder builder) { 237 super.onPrepareDialogBuilder(builder); 238 239 if (mEntries == null || mEntryValues == null) { 240 throw new IllegalStateException( 241 "ListPreference requires an entries array and an entryValues array."); 242 } 243 244 mClickedDialogEntryIndex = getValueIndex(); 245 builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex, 246 new DialogInterface.OnClickListener() { 247 public void onClick(DialogInterface dialog, int which) { 248 mClickedDialogEntryIndex = which; 249 250 /* 251 * Clicking on an item simulates the positive button 252 * click, and dismisses the dialog. 253 */ 254 ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE); 255 dialog.dismiss(); 256 } 257 }); 258 259 /* 260 * The typical interaction for list-based dialogs is to have 261 * click-on-an-item dismiss the dialog instead of the user having to 262 * press 'Ok'. 263 */ 264 builder.setPositiveButton(null, null); 265 } 266 267 @Override 268 protected void onDialogClosed(boolean positiveResult) { 269 super.onDialogClosed(positiveResult); 270 271 if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) { 272 String value = mEntryValues[mClickedDialogEntryIndex].toString(); 273 if (callChangeListener(value)) { 274 setValue(value); 275 } 276 } 277 } 278 279 @Override 280 protected Object onGetDefaultValue(TypedArray a, int index) { 281 return a.getString(index); 282 } 283 284 @Override 285 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { 286 setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue); 287 } 288 289 @Override 290 protected Parcelable onSaveInstanceState() { 291 final Parcelable superState = super.onSaveInstanceState(); 292 if (isPersistent()) { 293 // No need to save instance state since it's persistent 294 return superState; 295 } 296 297 final SavedState myState = new SavedState(superState); 298 myState.value = getValue(); 299 return myState; 300 } 301 302 @Override 303 protected void onRestoreInstanceState(Parcelable state) { 304 if (state == null || !state.getClass().equals(SavedState.class)) { 305 // Didn't save state for us in onSaveInstanceState 306 super.onRestoreInstanceState(state); 307 return; 308 } 309 310 SavedState myState = (SavedState) state; 311 super.onRestoreInstanceState(myState.getSuperState()); 312 setValue(myState.value); 313 } 314 315 private static class SavedState extends BaseSavedState { 316 String value; 317 318 public SavedState(Parcel source) { 319 super(source); 320 value = source.readString(); 321 } 322 323 @Override 324 public void writeToParcel(Parcel dest, int flags) { 325 super.writeToParcel(dest, flags); 326 dest.writeString(value); 327 } 328 329 public SavedState(Parcelable superState) { 330 super(superState); 331 } 332 333 public static final Parcelable.Creator<SavedState> CREATOR = 334 new Parcelable.Creator<SavedState>() { 335 public SavedState createFromParcel(Parcel in) { 336 return new SavedState(in); 337 } 338 339 public SavedState[] newArray(int size) { 340 return new SavedState[size]; 341 } 342 }; 343 } 344 345} 346