blob: c0c71af8639eec74785c024e2f272ee3c8f72263 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Tor Norbye7b9c9122013-05-30 16:48:33 -070019import android.annotation.ArrayRes;
Mathew Inwoodeac8d0a2018-08-17 13:51:26 +010020import android.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.app.AlertDialog.Builder;
22import android.content.Context;
23import android.content.DialogInterface;
24import android.content.res.TypedArray;
25import android.os.Parcel;
26import android.os.Parcelable;
Alan Viverette94c02a12013-07-23 14:43:37 -070027import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.util.AttributeSet;
29
30/**
31 * A {@link Preference} that displays a list of entries as
32 * a dialog.
33 * <p>
34 * This preference will store a string into the SharedPreferences. This string will be the value
35 * from the {@link #setEntryValues(CharSequence[])} array.
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -080036 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 * @attr ref android.R.styleable#ListPreference_entries
38 * @attr ref android.R.styleable#ListPreference_entryValues
39 */
40public class ListPreference extends DialogPreference {
41 private CharSequence[] mEntries;
42 private CharSequence[] mEntryValues;
43 private String mValue;
Kenny Rootba636df2010-07-13 07:53:32 -070044 private String mSummary;
Mathew Inwoodeac8d0a2018-08-17 13:51:26 +010045 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 private int mClickedDialogEntryIndex;
Alan Viverette94c02a12013-07-23 14:43:37 -070047 private boolean mValueSet;
Alan Viverette617feb92013-09-09 18:09:13 -070048
49 public ListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
50 super(context, attrs, defStyleAttr, defStyleRes);
51
52 TypedArray a = context.obtainStyledAttributes(
53 attrs, com.android.internal.R.styleable.ListPreference, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 mEntries = a.getTextArray(com.android.internal.R.styleable.ListPreference_entries);
55 mEntryValues = a.getTextArray(com.android.internal.R.styleable.ListPreference_entryValues);
56 a.recycle();
Kenny Rootba636df2010-07-13 07:53:32 -070057
58 /* Retrieve the Preference summary attribute since it's private
59 * in the Preference class.
60 */
61 a = context.obtainStyledAttributes(attrs,
Alan Viverette617feb92013-09-09 18:09:13 -070062 com.android.internal.R.styleable.Preference, defStyleAttr, defStyleRes);
Kenny Rootba636df2010-07-13 07:53:32 -070063 mSummary = a.getString(com.android.internal.R.styleable.Preference_summary);
64 a.recycle();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 }
Kenny Rootba636df2010-07-13 07:53:32 -070066
Alan Viverette617feb92013-09-09 18:09:13 -070067 public ListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
68 this(context, attrs, defStyleAttr, 0);
69 }
70
71 public ListPreference(Context context, AttributeSet attrs) {
Alan Viverette599d2a42013-09-16 13:48:29 -070072 this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle);
Alan Viverette617feb92013-09-09 18:09:13 -070073 }
74
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 public ListPreference(Context context) {
76 this(context, null);
77 }
78
79 /**
80 * Sets the human-readable entries to be shown in the list. This will be
81 * shown in subsequent dialogs.
82 * <p>
83 * Each entry must have a corresponding index in
84 * {@link #setEntryValues(CharSequence[])}.
85 *
86 * @param entries The entries.
87 * @see #setEntryValues(CharSequence[])
88 */
89 public void setEntries(CharSequence[] entries) {
90 mEntries = entries;
91 }
92
93 /**
94 * @see #setEntries(CharSequence[])
95 * @param entriesResId The entries array as a resource.
96 */
Tor Norbye7b9c9122013-05-30 16:48:33 -070097 public void setEntries(@ArrayRes int entriesResId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 setEntries(getContext().getResources().getTextArray(entriesResId));
99 }
100
101 /**
102 * The list of entries to be shown in the list in subsequent dialogs.
103 *
104 * @return The list as an array.
105 */
106 public CharSequence[] getEntries() {
107 return mEntries;
108 }
109
110 /**
111 * The array to find the value to save for a preference when an entry from
112 * entries is selected. If a user clicks on the second item in entries, the
113 * second item in this array will be saved to the preference.
114 *
115 * @param entryValues The array to be used as values to save for the preference.
116 */
117 public void setEntryValues(CharSequence[] entryValues) {
118 mEntryValues = entryValues;
119 }
120
121 /**
122 * @see #setEntryValues(CharSequence[])
123 * @param entryValuesResId The entry values array as a resource.
124 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700125 public void setEntryValues(@ArrayRes int entryValuesResId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
127 }
128
129 /**
130 * Returns the array of values to be saved for the preference.
131 *
132 * @return The array of values.
133 */
134 public CharSequence[] getEntryValues() {
135 return mEntryValues;
136 }
137
138 /**
139 * Sets the value of the key. This should be one of the entries in
140 * {@link #getEntryValues()}.
141 *
142 * @param value The value to set for the key.
143 */
144 public void setValue(String value) {
Alan Viverette94c02a12013-07-23 14:43:37 -0700145 // Always persist/notify the first time.
146 final boolean changed = !TextUtils.equals(mValue, value);
147 if (changed || !mValueSet) {
148 mValue = value;
149 mValueSet = true;
150 persistString(value);
151 if (changed) {
152 notifyChanged();
153 }
154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 }
156
157 /**
Kenny Rootba636df2010-07-13 07:53:32 -0700158 * Returns the summary of this ListPreference. If the summary
159 * has a {@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.
162 *
163 * @return the summary with appropriate string substitution
164 */
165 @Override
166 public CharSequence getSummary() {
167 final CharSequence entry = getEntry();
Alan Viverette13e13dd2014-10-21 17:05:07 -0700168 if (mSummary == null) {
Kenny Rootba636df2010-07-13 07:53:32 -0700169 return super.getSummary();
170 } else {
Alan Viverette13e13dd2014-10-21 17:05:07 -0700171 return String.format(mSummary, entry == null ? "" : entry);
Kenny Rootba636df2010-07-13 07:53:32 -0700172 }
173 }
174
175 /**
176 * Sets the summary for this Preference with a CharSequence.
177 * If the summary has a
178 * {@linkplain java.lang.String#format String formatting}
179 * marker in it (i.e. "%s" or "%1$s"), then the current entry
180 * value will be substituted in its place when it's retrieved.
181 *
182 * @param summary The summary for the preference.
183 */
184 @Override
185 public void setSummary(CharSequence summary) {
186 super.setSummary(summary);
187 if (summary == null && mSummary != null) {
188 mSummary = null;
189 } else if (summary != null && !summary.equals(mSummary)) {
190 mSummary = summary.toString();
191 }
192 }
193
194 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 * Sets the value to the given index from the entry values.
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800196 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 * @param index The index of the value to set.
198 */
199 public void setValueIndex(int index) {
200 if (mEntryValues != null) {
201 setValue(mEntryValues[index].toString());
202 }
203 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 /**
206 * Returns the value of the key. This should be one of the entries in
207 * {@link #getEntryValues()}.
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800208 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 * @return The value of the key.
210 */
211 public String getValue() {
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800212 return mValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 /**
216 * Returns the entry corresponding to the current value.
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800217 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 * @return The entry corresponding to the current value, or null.
219 */
220 public CharSequence getEntry() {
221 int index = getValueIndex();
222 return index >= 0 && mEntries != null ? mEntries[index] : null;
223 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 /**
226 * Returns the index of the given value (in the entry values array).
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800227 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 * @param value The value whose index should be returned.
229 * @return The index of the value, or -1 if not found.
230 */
231 public int findIndexOfValue(String value) {
232 if (value != null && mEntryValues != null) {
233 for (int i = mEntryValues.length - 1; i >= 0; i--) {
234 if (mEntryValues[i].equals(value)) {
235 return i;
236 }
237 }
238 }
239 return -1;
240 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 private int getValueIndex() {
243 return findIndexOfValue(mValue);
244 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 @Override
247 protected void onPrepareDialogBuilder(Builder builder) {
248 super.onPrepareDialogBuilder(builder);
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 if (mEntries == null || mEntryValues == null) {
251 throw new IllegalStateException(
252 "ListPreference requires an entries array and an entryValues array.");
253 }
254
255 mClickedDialogEntryIndex = getValueIndex();
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800256 builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 new DialogInterface.OnClickListener() {
258 public void onClick(DialogInterface dialog, int which) {
259 mClickedDialogEntryIndex = which;
260
261 /*
262 * Clicking on an item simulates the positive button
263 * click, and dismisses the dialog.
264 */
265 ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800266 postDismiss();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 }
268 });
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 /*
271 * The typical interaction for list-based dialogs is to have
272 * click-on-an-item dismiss the dialog instead of the user having to
273 * press 'Ok'.
274 */
275 builder.setPositiveButton(null, null);
276 }
277
278 @Override
279 protected void onDialogClosed(boolean positiveResult) {
280 super.onDialogClosed(positiveResult);
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
283 String value = mEntryValues[mClickedDialogEntryIndex].toString();
284 if (callChangeListener(value)) {
285 setValue(value);
286 }
287 }
288 }
289
290 @Override
291 protected Object onGetDefaultValue(TypedArray a, int index) {
292 return a.getString(index);
293 }
294
295 @Override
296 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
297 setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
298 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 @Override
301 protected Parcelable onSaveInstanceState() {
302 final Parcelable superState = super.onSaveInstanceState();
303 if (isPersistent()) {
304 // No need to save instance state since it's persistent
305 return superState;
306 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 final SavedState myState = new SavedState(superState);
309 myState.value = getValue();
310 return myState;
311 }
312
313 @Override
314 protected void onRestoreInstanceState(Parcelable state) {
315 if (state == null || !state.getClass().equals(SavedState.class)) {
316 // Didn't save state for us in onSaveInstanceState
317 super.onRestoreInstanceState(state);
318 return;
319 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 SavedState myState = (SavedState) state;
322 super.onRestoreInstanceState(myState.getSuperState());
323 setValue(myState.value);
324 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 private static class SavedState extends BaseSavedState {
327 String value;
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 public SavedState(Parcel source) {
330 super(source);
331 value = source.readString();
332 }
333
334 @Override
335 public void writeToParcel(Parcel dest, int flags) {
336 super.writeToParcel(dest, flags);
337 dest.writeString(value);
338 }
339
340 public SavedState(Parcelable superState) {
341 super(superState);
342 }
343
344 public static final Parcelable.Creator<SavedState> CREATOR =
345 new Parcelable.Creator<SavedState>() {
346 public SavedState createFromParcel(Parcel in) {
347 return new SavedState(in);
348 }
349
350 public SavedState[] newArray(int size) {
351 return new SavedState[size];
352 }
353 };
354 }
Siarhei Vishniakou5692a8b2018-03-09 15:38:12 -0800355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356}