blob: 6c4c20f9abe0031606a5444406b01f000e48d0b1 [file] [log] [blame]
Adam Powell212db7d2010-04-08 16:24:46 -07001/*
2 * Copyright (C) 2010 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.util.AttributeSet;
26
27import java.util.HashSet;
28import java.util.Set;
29
30/**
31 * A {@link Preference} that displays a list of entries as
32 * a dialog.
33 * <p>
34 * This preference will store a set of strings into the SharedPreferences.
35 * This set will contain one or more values from the
36 * {@link #setEntryValues(CharSequence[])} array.
37 *
38 * @attr ref android.R.styleable#MultiSelectListPreference_entries
39 * @attr ref android.R.styleable#MultiSelectListPreference_entryValues
40 */
41public class MultiSelectListPreference extends DialogPreference {
42 private CharSequence[] mEntries;
43 private CharSequence[] mEntryValues;
44 private Set<String> mValues = new HashSet<String>();
45 private Set<String> mNewValues = new HashSet<String>();
46 private boolean mPreferenceChanged;
Alan Viverette617feb92013-09-09 18:09:13 -070047
48 public MultiSelectListPreference(
49 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
50 super(context, attrs, defStyleAttr, defStyleRes);
51
52 final TypedArray a = context.obtainStyledAttributes(attrs,
53 com.android.internal.R.styleable.MultiSelectListPreference, defStyleAttr,
54 defStyleRes);
Adam Powell212db7d2010-04-08 16:24:46 -070055 mEntries = a.getTextArray(com.android.internal.R.styleable.MultiSelectListPreference_entries);
56 mEntryValues = a.getTextArray(com.android.internal.R.styleable.MultiSelectListPreference_entryValues);
57 a.recycle();
58 }
Alan Viverette617feb92013-09-09 18:09:13 -070059
60 public MultiSelectListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
61 this(context, attrs, defStyleAttr, 0);
62 }
63
64 public MultiSelectListPreference(Context context, AttributeSet attrs) {
Alan Viverette599d2a42013-09-16 13:48:29 -070065 this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle);
Alan Viverette617feb92013-09-09 18:09:13 -070066 }
Adam Powell212db7d2010-04-08 16:24:46 -070067
68 public MultiSelectListPreference(Context context) {
69 this(context, null);
70 }
71
72 /**
73 * Sets the human-readable entries to be shown in the list. This will be
74 * shown in subsequent dialogs.
75 * <p>
76 * Each entry must have a corresponding index in
77 * {@link #setEntryValues(CharSequence[])}.
78 *
79 * @param entries The entries.
80 * @see #setEntryValues(CharSequence[])
81 */
82 public void setEntries(CharSequence[] entries) {
83 mEntries = entries;
84 }
85
86 /**
87 * @see #setEntries(CharSequence[])
88 * @param entriesResId The entries array as a resource.
89 */
90 public void setEntries(int entriesResId) {
91 setEntries(getContext().getResources().getTextArray(entriesResId));
92 }
93
94 /**
95 * The list of entries to be shown in the list in subsequent dialogs.
96 *
97 * @return The list as an array.
98 */
99 public CharSequence[] getEntries() {
100 return mEntries;
101 }
102
103 /**
104 * The array to find the value to save for a preference when an entry from
105 * entries is selected. If a user clicks on the second item in entries, the
106 * second item in this array will be saved to the preference.
107 *
108 * @param entryValues The array to be used as values to save for the preference.
109 */
110 public void setEntryValues(CharSequence[] entryValues) {
111 mEntryValues = entryValues;
112 }
113
114 /**
115 * @see #setEntryValues(CharSequence[])
116 * @param entryValuesResId The entry values array as a resource.
117 */
118 public void setEntryValues(int entryValuesResId) {
119 setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
120 }
121
122 /**
123 * Returns the array of values to be saved for the preference.
124 *
125 * @return The array of values.
126 */
127 public CharSequence[] getEntryValues() {
128 return mEntryValues;
129 }
130
131 /**
132 * Sets the value of the key. This should contain entries in
133 * {@link #getEntryValues()}.
134 *
135 * @param values The values to set for the key.
136 */
137 public void setValues(Set<String> values) {
Amith Yamasanicd9ea082012-05-15 17:17:24 -0700138 mValues.clear();
139 mValues.addAll(values);
140
Adam Powell212db7d2010-04-08 16:24:46 -0700141 persistStringSet(values);
142 }
143
144 /**
145 * Retrieves the current value of the key.
146 */
147 public Set<String> getValues() {
148 return mValues;
149 }
150
151 /**
152 * Returns the index of the given value (in the entry values array).
153 *
154 * @param value The value whose index should be returned.
155 * @return The index of the value, or -1 if not found.
156 */
157 public int findIndexOfValue(String value) {
158 if (value != null && mEntryValues != null) {
159 for (int i = mEntryValues.length - 1; i >= 0; i--) {
160 if (mEntryValues[i].equals(value)) {
161 return i;
162 }
163 }
164 }
165 return -1;
166 }
167
168 @Override
169 protected void onPrepareDialogBuilder(Builder builder) {
170 super.onPrepareDialogBuilder(builder);
171
172 if (mEntries == null || mEntryValues == null) {
173 throw new IllegalStateException(
174 "MultiSelectListPreference requires an entries array and " +
175 "an entryValues array.");
176 }
177
178 boolean[] checkedItems = getSelectedItems();
179 builder.setMultiChoiceItems(mEntries, checkedItems,
180 new DialogInterface.OnMultiChoiceClickListener() {
181 public void onClick(DialogInterface dialog, int which, boolean isChecked) {
182 if (isChecked) {
Justin Kohece60fb2011-04-07 19:40:29 -0700183 mPreferenceChanged |= mNewValues.add(mEntryValues[which].toString());
Adam Powell212db7d2010-04-08 16:24:46 -0700184 } else {
Justin Kohece60fb2011-04-07 19:40:29 -0700185 mPreferenceChanged |= mNewValues.remove(mEntryValues[which].toString());
Adam Powell212db7d2010-04-08 16:24:46 -0700186 }
187 }
188 });
189 mNewValues.clear();
190 mNewValues.addAll(mValues);
191 }
192
193 private boolean[] getSelectedItems() {
Justin Kohece60fb2011-04-07 19:40:29 -0700194 final CharSequence[] entries = mEntryValues;
Adam Powell212db7d2010-04-08 16:24:46 -0700195 final int entryCount = entries.length;
196 final Set<String> values = mValues;
197 boolean[] result = new boolean[entryCount];
198
199 for (int i = 0; i < entryCount; i++) {
200 result[i] = values.contains(entries[i].toString());
201 }
202
203 return result;
204 }
205
206 @Override
207 protected void onDialogClosed(boolean positiveResult) {
208 super.onDialogClosed(positiveResult);
209
210 if (positiveResult && mPreferenceChanged) {
211 final Set<String> values = mNewValues;
212 if (callChangeListener(values)) {
213 setValues(values);
214 }
215 }
216 mPreferenceChanged = false;
217 }
218
219 @Override
220 protected Object onGetDefaultValue(TypedArray a, int index) {
221 final CharSequence[] defaultValues = a.getTextArray(index);
222 final int valueCount = defaultValues.length;
223 final Set<String> result = new HashSet<String>();
224
225 for (int i = 0; i < valueCount; i++) {
226 result.add(defaultValues[i].toString());
227 }
228
229 return result;
230 }
231
232 @Override
233 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
234 setValues(restoreValue ? getPersistedStringSet(mValues) : (Set<String>) defaultValue);
235 }
236
237 @Override
238 protected Parcelable onSaveInstanceState() {
239 final Parcelable superState = super.onSaveInstanceState();
240 if (isPersistent()) {
241 // No need to save instance state
242 return superState;
243 }
244
245 final SavedState myState = new SavedState(superState);
246 myState.values = getValues();
247 return myState;
248 }
249
250 private static class SavedState extends BaseSavedState {
251 Set<String> values;
252
253 public SavedState(Parcel source) {
254 super(source);
255 values = new HashSet<String>();
256 String[] strings = source.readStringArray();
257
258 final int stringCount = strings.length;
259 for (int i = 0; i < stringCount; i++) {
260 values.add(strings[i]);
261 }
262 }
263
264 public SavedState(Parcelable superState) {
265 super(superState);
266 }
267
268 @Override
269 public void writeToParcel(Parcel dest, int flags) {
270 super.writeToParcel(dest, flags);
271 dest.writeStringArray(values.toArray(new String[0]));
272 }
273
274 public static final Parcelable.Creator<SavedState> CREATOR =
275 new Parcelable.Creator<SavedState>() {
276 public SavedState createFromParcel(Parcel in) {
277 return new SavedState(in);
278 }
279
280 public SavedState[] newArray(int size) {
281 return new SavedState[size];
282 }
283 };
284 }
285}