package ca.rmen.android.networkmonitor.app.prefs.hack;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v14.preference.MultiSelectListPreference;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceDialogFragmentCompat;
import java.util.HashSet;
import java.util.Set;
/**
* This class is a hack to allow us to use a MultiSelectListPreference with the v7
* PreferenceCompat library.
* This class will not actually function on older devices (< API 11 for sure, not sure if
* it will work on API 12 and 13).
* <p/>
* It may be possible to avoid this hack, and to use only v14 preference classes (ie
* PreferenceFragment instead of PreferenceFragmentCompat), but they may be more difficult
* to theme. I noticed that the "ok" and "cancel" buttons of the preference dialogs
* were not in my app's theme. The theme works with PreferenceFragmentCompat (v7).
* <p/>
* This code was partially obtained from Android Studio's decompiling of
* MultiSelectListPreferenceDialogFragment.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MultiSelectListPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat
implements DialogPreference.TargetFragment {
private final Set<String> mNewValues = new HashSet<>();
private boolean mPreferenceChanged;
public MultiSelectListPreferenceDialogFragmentCompat() {
}
public static MultiSelectListPreferenceDialogFragmentCompat newInstance(String key) {
MultiSelectListPreferenceDialogFragmentCompat fragment = new MultiSelectListPreferenceDialogFragmentCompat();
Bundle b = new Bundle(1);
b.putString("key", key);
fragment.setArguments(b);
return fragment;
}
/**
* We set the AlertDialog to display a multi-choice list. We register a listener: when the user
* checks or un-checks values, we store the list of all selected values.
*/
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
final MultiSelectListPreference preference = getListPreference();
if (preference.getEntries() != null && preference.getEntryValues() != null) {
boolean[] checkedItems = getSelectedItems();
builder.setMultiChoiceItems(preference.getEntries(), checkedItems, (dialog, which, isChecked) -> {
mPreferenceChanged = true;
if (isChecked) {
mNewValues.add(preference.getEntryValues()[which].toString());
} else {
mNewValues.remove(preference.getEntryValues()[which].toString());
}
});
mNewValues.clear();
mNewValues.addAll(preference.getValues());
} else {
throw new IllegalStateException("MultiSelectListPreference requires an entries array and an entryValues array.");
}
}
/**
* If the user tapped on "ok", we update our Preference's selected values, based on the values
* our alert dialog listener saved.
* @param positiveResult true if the user tapped on "ok".
*/
public void onDialogClosed(boolean positiveResult) {
MultiSelectListPreference preference = getListPreference();
if (positiveResult && mPreferenceChanged) {
Set<String> values = mNewValues;
if (preference.callChangeListener(values)) {
preference.setValues(values);
}
}
mPreferenceChanged = false;
}
/**
* @return a list of the checked/unchecked state of all the list entries.
*/
private boolean[] getSelectedItems() {
MultiSelectListPreference preference = getListPreference();
CharSequence[] entries = preference.getEntryValues();
Set<String> values = preference.getValues();
boolean[] result = new boolean[entries.length];
for (int i = 0; i < entries.length; i++) {
result[i] = values.contains(entries[i].toString());
}
return result;
}
private MultiSelectListPreference getListPreference() {
return (MultiSelectListPreference) getPreference();
}
@Override
public Preference findPreference(CharSequence charSequence) {
return getPreference();
}
}