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