mobile/android/base/preferences/MultiChoicePreference.java

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:e0e4e2297596
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 package org.mozilla.gecko.preferences;
7
8 import org.mozilla.gecko.R;
9 import org.mozilla.gecko.GeckoSharedPrefs;
10 import org.mozilla.gecko.util.ThreadUtils;
11
12 import android.app.AlertDialog;
13 import android.app.AlertDialog.Builder;
14 import android.content.Context;
15 import android.content.DialogInterface;
16 import android.content.res.TypedArray;
17 import android.preference.DialogPreference;
18 import android.util.AttributeSet;
19 import android.widget.Button;
20
21 class MultiChoicePreference extends DialogPreference {
22 private static final String LOGTAG = "GeckoMultiChoicePreference";
23
24 private boolean mValues[];
25 private boolean mPrevValues[];
26 private CharSequence mEntryKeys[];
27 private CharSequence mEntries[];
28 private CharSequence mInitialValues[];
29
30 public MultiChoicePreference(Context context, AttributeSet attrs) {
31 super(context, attrs);
32
33 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiChoicePreference);
34 mEntries = a.getTextArray(R.styleable.MultiChoicePreference_entries);
35 mEntryKeys = a.getTextArray(R.styleable.MultiChoicePreference_entryKeys);
36 mInitialValues = a.getTextArray(R.styleable.MultiChoicePreference_initialValues);
37 a.recycle();
38
39 loadPersistedValues();
40 }
41
42 public MultiChoicePreference(Context context) {
43 this(context, null);
44 }
45
46 /**
47 * Sets the human-readable entries to be shown in the list. This will be
48 * shown in subsequent dialogs.
49 * <p>
50 * Each entry must have a corresponding index in
51 * {@link #setEntryKeys(CharSequence[])} and
52 * {@link #setInitialValues(CharSequence[])}.
53 *
54 * @param entries The entries.
55 */
56 public void setEntries(CharSequence[] entries) {
57 mEntries = entries.clone();
58 }
59
60 /**
61 * @param entriesResId The entries array as a resource.
62 */
63 public void setEntries(int entriesResId) {
64 setEntries(getContext().getResources().getTextArray(entriesResId));
65 }
66
67 /**
68 * Sets the preference keys for preferences shown in the list.
69 *
70 * @param entryKeys The entry keys.
71 */
72 public void setEntryKeys(CharSequence[] entryKeys) {
73 mEntryKeys = entryKeys.clone();
74 loadPersistedValues();
75 }
76
77 /**
78 * @param entryKeysResId The entryKeys array as a resource.
79 */
80 public void setEntryKeys(int entryKeysResId) {
81 setEntryKeys(getContext().getResources().getTextArray(entryKeysResId));
82 }
83
84 /**
85 * The array of initial entry values in this list. Each entryValue
86 * corresponds to an entryKey. These values are used if a) the preference
87 * isn't persisted, or b) the preference is persisted but hasn't yet been
88 * set.
89 *
90 * @param initialValues The entry values
91 */
92 public void setInitialValues(CharSequence[] initialValues) {
93 mInitialValues = initialValues.clone();
94 loadPersistedValues();
95 }
96
97 /**
98 * @param initialValuesResId The initialValues array as a resource.
99 */
100 public void setInitialValues(int initialValuesResId) {
101 setInitialValues(getContext().getResources().getTextArray(initialValuesResId));
102 }
103
104 /**
105 * The list of translated strings corresponding to each preference.
106 *
107 * @return The array of entries.
108 */
109 public CharSequence[] getEntries() {
110 return mEntries.clone();
111 }
112
113 /**
114 * The list of keys corresponding to each preference.
115 *
116 * @return The array of keys.
117 */
118 public CharSequence[] getEntryKeys() {
119 return mEntryKeys.clone();
120 }
121
122 /**
123 * The list of initial values for each preference. Each string in this list
124 * should be either "true" or "false".
125 *
126 * @return The array of initial values.
127 */
128 public CharSequence[] getInitialValues() {
129 return mInitialValues.clone();
130 }
131
132 /**
133 * The list of values for each preference. These values are updated after
134 * the dialog has been displayed.
135 *
136 * @return The array of values.
137 */
138 public boolean[] getValues() {
139 return mValues.clone();
140 }
141
142 @Override
143 protected void onPrepareDialogBuilder(Builder builder) {
144 if (mEntries == null || mEntryKeys == null || mInitialValues == null) {
145 throw new IllegalStateException(
146 "MultiChoicePreference requires entries, entryKeys, and initialValues arrays.");
147 }
148
149 if (mEntries.length != mEntryKeys.length || mEntryKeys.length != mInitialValues.length) {
150 throw new IllegalStateException(
151 "MultiChoicePreference entries, entryKeys, and initialValues arrays must be the same length");
152 }
153
154 builder.setMultiChoiceItems(mEntries, mValues, new DialogInterface.OnMultiChoiceClickListener() {
155 @Override
156 public void onClick(DialogInterface dialog, int which, boolean val) {
157 // mValues is automatically updated when checkboxes are clicked
158
159 // enable positive button only if at least one item is checked
160 boolean enabled = false;
161 for (int i = 0; i < mValues.length; i++) {
162 if (mValues[i]) {
163 enabled = true;
164 break;
165 }
166 }
167 Button button = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
168 if (button.isEnabled() != enabled)
169 button.setEnabled(enabled);
170 }
171 });
172 }
173
174 @Override
175 protected void onDialogClosed(boolean positiveResult) {
176 if (mPrevValues == null || mInitialValues == null) {
177 // Initialization is done asynchronously, so these values may not
178 // have been set before the dialog was closed.
179 return;
180 }
181
182 if (!positiveResult) {
183 // user cancelled; reset checkbox values to their previous state
184 mValues = mPrevValues.clone();
185 return;
186 } else {
187 mPrevValues = mValues.clone();
188 }
189
190 ThreadUtils.postToBackgroundThread(new Runnable() {
191 @Override
192 public void run() {
193 for (int i = 0; i < mEntryKeys.length; i++) {
194 String key = mEntryKeys[i].toString();
195 persistBoolean(key, mValues[i]);
196 }
197 }
198 });
199 }
200
201 protected boolean persistBoolean(String key, boolean value) {
202 if (isPersistent()) {
203 if (value == getPersistedBoolean(!value)) {
204 // It's already there, so the same as persisting
205 return true;
206 }
207
208 GeckoSharedPrefs.forApp(getContext())
209 .edit().putBoolean(key, value).commit();
210 return true;
211 }
212 return false;
213 }
214
215 protected boolean getPersistedBoolean(String key, boolean defaultReturnValue) {
216 if (!isPersistent())
217 return defaultReturnValue;
218
219 return GeckoSharedPrefs.forApp(getContext())
220 .getBoolean(key, defaultReturnValue);
221 }
222
223 /**
224 * Loads persistent prefs from shared preferences. If the preferences
225 * aren't persistent or haven't yet been stored, they will be set to their
226 * initial values.
227 */
228 private void loadPersistedValues() {
229 if (mEntryKeys == null || mInitialValues == null)
230 return;
231
232 final int entryCount = mEntryKeys.length;
233 if (entryCount != mEntries.length || entryCount != mInitialValues.length) {
234 throw new IllegalStateException(
235 "MultiChoicePreference entryKeys and initialValues arrays must be the same length");
236 }
237
238 mValues = new boolean[entryCount];
239 ThreadUtils.postToBackgroundThread(new Runnable() {
240 @Override
241 public void run() {
242 for (int i = 0; i < entryCount; i++) {
243 String key = mEntryKeys[i].toString();
244 boolean initialValue = mInitialValues[i].equals("true");
245 mValues[i] = getPersistedBoolean(key, initialValue);
246 }
247 mPrevValues = mValues.clone();
248 }
249 });
250 }
251 }

mercurial