diff options
Diffstat (limited to 'mobile/android/base/java/org/mozilla/gecko/preferences/MultiChoicePreference.java')
-rw-r--r-- | mobile/android/base/java/org/mozilla/gecko/preferences/MultiChoicePreference.java | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/mobile/android/base/java/org/mozilla/gecko/preferences/MultiChoicePreference.java b/mobile/android/base/java/org/mozilla/gecko/preferences/MultiChoicePreference.java new file mode 100644 index 000000000..5749bf29d --- /dev/null +++ b/mobile/android/base/java/org/mozilla/gecko/preferences/MultiChoicePreference.java @@ -0,0 +1,271 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.preferences; + +import org.mozilla.gecko.R; +import org.mozilla.gecko.GeckoSharedPrefs; +import org.mozilla.gecko.util.PrefUtils; +import org.mozilla.gecko.util.ThreadUtils; + +import android.app.AlertDialog.Builder; +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.TypedArray; +import android.content.SharedPreferences; +import android.preference.DialogPreference; +import android.util.AttributeSet; + +import java.util.HashSet; +import java.util.Set; + +class MultiChoicePreference extends DialogPreference implements DialogInterface.OnMultiChoiceClickListener { + private static final String LOGTAG = "GeckoMultiChoicePreference"; + + private boolean mValues[]; + private boolean mPrevValues[]; + private CharSequence mEntryValues[]; + private CharSequence mEntries[]; + private CharSequence mInitialValues[]; + + public MultiChoicePreference(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiChoicePreference); + mEntries = a.getTextArray(R.styleable.MultiChoicePreference_entries); + mEntryValues = a.getTextArray(R.styleable.MultiChoicePreference_entryValues); + mInitialValues = a.getTextArray(R.styleable.MultiChoicePreference_initialValues); + a.recycle(); + + loadPersistedValues(); + } + + public MultiChoicePreference(Context context) { + this(context, null); + } + + /** + * Sets the human-readable entries to be shown in the list. This will be + * shown in subsequent dialogs. + * <p> + * Each entry must have a corresponding index in + * {@link #setEntryValues(CharSequence[])} and + * {@link #setInitialValues(CharSequence[])}. + * + * @param entries The entries. + */ + public void setEntries(CharSequence[] entries) { + mEntries = entries.clone(); + } + + /** + * @param entriesResId The entries array as a resource. + */ + public void setEntries(int entriesResId) { + setEntries(getContext().getResources().getTextArray(entriesResId)); + } + + /** + * Sets the preference values for preferences shown in the list. + * + * @param entryValues The entry values. + */ + public void setEntryValues(CharSequence[] entryValues) { + mEntryValues = entryValues.clone(); + loadPersistedValues(); + } + + /** + * Entry values define a separate pref for each row in the dialog. + * + * @param entryValuesResId The entryValues array as a resource. + */ + public void setEntryValues(int entryValuesResId) { + setEntryValues(getContext().getResources().getTextArray(entryValuesResId)); + } + + /** + * The array of initial entry values in this list. Each entryValue + * corresponds to an entryKey. These values are used if a) the preference + * isn't persisted, or b) the preference is persisted but hasn't yet been + * set. + * + * @param initialValues The entry values + */ + public void setInitialValues(CharSequence[] initialValues) { + mInitialValues = initialValues.clone(); + loadPersistedValues(); + } + + /** + * @param initialValuesResId The initialValues array as a resource. + */ + public void setInitialValues(int initialValuesResId) { + setInitialValues(getContext().getResources().getTextArray(initialValuesResId)); + } + + /** + * The list of translated strings corresponding to each preference. + * + * @return The array of entries. + */ + public CharSequence[] getEntries() { + return mEntries.clone(); + } + + /** + * The list of values corresponding to each preference. + * + * @return The array of values. + */ + public CharSequence[] getEntryValues() { + return mEntryValues.clone(); + } + + /** + * The list of initial values for each preference. Each string in this list + * should be either "true" or "false". + * + * @return The array of initial values. + */ + public CharSequence[] getInitialValues() { + return mInitialValues.clone(); + } + + public void setValue(final int i, final boolean value) { + mValues[i] = value; + mPrevValues = mValues.clone(); + } + + /** + * The list of values for each preference. These values are updated after + * the dialog has been displayed. + * + * @return The array of values. + */ + public Set<String> getValues() { + final Set<String> values = new HashSet<String>(); + + if (mValues == null) { + return values; + } + + for (int i = 0; i < mValues.length; i++) { + if (mValues[i]) { + values.add(mEntryValues[i].toString()); + } + } + + return values; + } + + @Override + public void onClick(DialogInterface dialog, int which, boolean val) { + } + + @Override + protected void onPrepareDialogBuilder(Builder builder) { + if (mEntries == null || mInitialValues == null || mEntryValues == null) { + throw new IllegalStateException( + "MultiChoicePreference requires entries, entryValues, and initialValues arrays."); + } + + if (mEntries.length != mEntryValues.length || mEntries.length != mInitialValues.length) { + throw new IllegalStateException( + "MultiChoicePreference entries, entryValues, and initialValues arrays must be the same length"); + } + + builder.setMultiChoiceItems(mEntries, mValues, this); + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + if (mPrevValues == null || mInitialValues == null) { + // Initialization is done asynchronously, so these values may not + // have been set before the dialog was closed. + return; + } + + if (!positiveResult) { + // user cancelled; reset checkbox values to their previous state + mValues = mPrevValues.clone(); + return; + } + + mPrevValues = mValues.clone(); + + if (!callChangeListener(getValues())) { + return; + } + + persist(); + } + + /* Persists the current data stored by this pref to SharedPreferences. */ + public boolean persist() { + if (isPersistent()) { + final SharedPreferences.Editor edit = GeckoSharedPrefs.forProfile(getContext()).edit(); + final boolean res = persist(edit); + edit.apply(); + return res; + } + + return false; + } + + /* Internal persist method. Take an edit so that multiple prefs can be persisted in a single commit. */ + protected boolean persist(SharedPreferences.Editor edit) { + if (isPersistent()) { + Set<String> vals = getValues(); + PrefUtils.putStringSet(edit, getKey(), vals).apply();; + return true; + } + + return false; + } + + /* Returns a list of EntryValues that are currently enabled. */ + public Set<String> getPersistedStrings(Set<String> defaultVal) { + if (!isPersistent()) { + return defaultVal; + } + + final SharedPreferences prefs = GeckoSharedPrefs.forProfile(getContext()); + return PrefUtils.getStringSet(prefs, getKey(), defaultVal); + } + + /** + * Loads persistent prefs from shared preferences. If the preferences + * aren't persistent or haven't yet been stored, they will be set to their + * initial values. + */ + protected void loadPersistedValues() { + final int entryCount = mInitialValues.length; + mValues = new boolean[entryCount]; + + if (entryCount != mEntries.length || entryCount != mEntryValues.length) { + throw new IllegalStateException( + "MultiChoicePreference entryValues and initialValues arrays must be the same length"); + } + + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + final Set<String> stringVals = getPersistedStrings(null); + + for (int i = 0; i < entryCount; i++) { + if (stringVals != null) { + mValues[i] = stringVals.contains(mEntryValues[i]); + } else { + final boolean defaultVal = mInitialValues[i].equals("true"); + mValues[i] = defaultVal; + } + } + + mPrevValues = mValues.clone(); + } + }); + } +} |