Home | History | Annotate | Download | only in preference
      1 /*
      2  * Copyright (C) 2012 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 
     17 package android.preference;
     18 
     19 import java.util.Arrays;
     20 
     21 import android.app.AlertDialog.Builder;
     22 import android.content.Context;
     23 import android.content.DialogInterface;
     24 import android.content.res.TypedArray;
     25 import android.os.Parcel;
     26 import android.os.Parcelable;
     27 import android.util.AttributeSet;
     28 
     29 /**
     30  * @hide
     31  * A {@link Preference} that displays a list of entries as
     32  * a dialog which allow the user to toggle each individually on and off.
     33  *
     34  * @attr ref android.R.styleable#ListPreference_entries
     35  * @attr ref android.R.styleable#ListPreference_entryValues
     36  */
     37 public class MultiCheckPreference extends DialogPreference {
     38     private CharSequence[] mEntries;
     39     private String[] mEntryValues;
     40     private boolean[] mSetValues;
     41     private boolean[] mOrigValues;
     42     private String mSummary;
     43 
     44     public MultiCheckPreference(Context context, AttributeSet attrs) {
     45         super(context, attrs);
     46 
     47         TypedArray a = context.obtainStyledAttributes(attrs,
     48                 com.android.internal.R.styleable.ListPreference, 0, 0);
     49         mEntries = a.getTextArray(com.android.internal.R.styleable.ListPreference_entries);
     50         if (mEntries != null) {
     51             setEntries(mEntries);
     52         }
     53         setEntryValuesCS(a.getTextArray(
     54                 com.android.internal.R.styleable.ListPreference_entryValues));
     55         a.recycle();
     56 
     57         /* Retrieve the Preference summary attribute since it's private
     58          * in the Preference class.
     59          */
     60         a = context.obtainStyledAttributes(attrs,
     61                 com.android.internal.R.styleable.Preference, 0, 0);
     62         mSummary = a.getString(com.android.internal.R.styleable.Preference_summary);
     63         a.recycle();
     64     }
     65 
     66     public MultiCheckPreference(Context context) {
     67         this(context, null);
     68     }
     69 
     70     /**
     71      * Sets the human-readable entries to be shown in the list. This will be
     72      * shown in subsequent dialogs.
     73      * <p>
     74      * Each entry must have a corresponding index in
     75      * {@link #setEntryValues(CharSequence[])}.
     76      *
     77      * @param entries The entries.
     78      * @see #setEntryValues(CharSequence[])
     79      */
     80     public void setEntries(CharSequence[] entries) {
     81         mEntries = entries;
     82         mSetValues = new boolean[entries.length];
     83         mOrigValues = new boolean[entries.length];
     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(String[] entryValues) {
    111         mEntryValues = entryValues;
    112         Arrays.fill(mSetValues, false);
    113         Arrays.fill(mOrigValues, false);
    114     }
    115 
    116     /**
    117      * @see #setEntryValues(CharSequence[])
    118      * @param entryValuesResId The entry values array as a resource.
    119      */
    120     public void setEntryValues(int entryValuesResId) {
    121         setEntryValuesCS(getContext().getResources().getTextArray(entryValuesResId));
    122     }
    123 
    124     private void setEntryValuesCS(CharSequence[] values) {
    125         setValues(null);
    126         if (values != null) {
    127             mEntryValues = new String[values.length];
    128             for (int i=0; i<values.length; i++) {
    129                 mEntryValues[i] = values[i].toString();
    130             }
    131         }
    132     }
    133 
    134     /**
    135      * Returns the array of values to be saved for the preference.
    136      *
    137      * @return The array of values.
    138      */
    139     public String[] getEntryValues() {
    140         return mEntryValues;
    141     }
    142 
    143     /**
    144      * Get the boolean state of a given value.
    145      */
    146     public boolean getValue(int index) {
    147         return mSetValues[index];
    148     }
    149 
    150     /**
    151      * Set the boolean state of a given value.
    152      */
    153     public void setValue(int index, boolean state) {
    154         mSetValues[index] = state;
    155     }
    156 
    157     /**
    158      * Sets the current values.
    159      */
    160     public void setValues(boolean[] values) {
    161         if (mSetValues != null) {
    162             Arrays.fill(mSetValues, false);
    163             Arrays.fill(mOrigValues, false);
    164             if (values != null) {
    165                 System.arraycopy(values, 0, mSetValues, 0,
    166                         values.length < mSetValues.length ? values.length : mSetValues.length);
    167             }
    168         }
    169     }
    170 
    171     /**
    172      * Returns the summary of this ListPreference. If the summary
    173      * has a {@linkplain java.lang.String#format String formatting}
    174      * marker in it (i.e. "%s" or "%1$s"), then the current entry
    175      * value will be substituted in its place.
    176      *
    177      * @return the summary with appropriate string substitution
    178      */
    179     @Override
    180     public CharSequence getSummary() {
    181         if (mSummary == null) {
    182             return super.getSummary();
    183         } else {
    184             return mSummary;
    185         }
    186     }
    187 
    188     /**
    189      * Sets the summary for this Preference with a CharSequence.
    190      * If the summary has a
    191      * {@linkplain java.lang.String#format String formatting}
    192      * marker in it (i.e. "%s" or "%1$s"), then the current entry
    193      * value will be substituted in its place when it's retrieved.
    194      *
    195      * @param summary The summary for the preference.
    196      */
    197     @Override
    198     public void setSummary(CharSequence summary) {
    199         super.setSummary(summary);
    200         if (summary == null && mSummary != null) {
    201             mSummary = null;
    202         } else if (summary != null && !summary.equals(mSummary)) {
    203             mSummary = summary.toString();
    204         }
    205     }
    206 
    207     /**
    208      * Returns the currently selected values.
    209      */
    210     public boolean[] getValues() {
    211         return mSetValues;
    212     }
    213 
    214     /**
    215      * Returns the index of the given value (in the entry values array).
    216      *
    217      * @param value The value whose index should be returned.
    218      * @return The index of the value, or -1 if not found.
    219      */
    220     public int findIndexOfValue(String value) {
    221         if (value != null && mEntryValues != null) {
    222             for (int i = mEntryValues.length - 1; i >= 0; i--) {
    223                 if (mEntryValues[i].equals(value)) {
    224                     return i;
    225                 }
    226             }
    227         }
    228         return -1;
    229     }
    230 
    231     @Override
    232     protected void onPrepareDialogBuilder(Builder builder) {
    233         super.onPrepareDialogBuilder(builder);
    234 
    235         if (mEntries == null || mEntryValues == null) {
    236             throw new IllegalStateException(
    237                     "ListPreference requires an entries array and an entryValues array.");
    238         }
    239 
    240         mOrigValues = Arrays.copyOf(mSetValues, mSetValues.length);
    241         builder.setMultiChoiceItems(mEntries, mSetValues,
    242                 new DialogInterface.OnMultiChoiceClickListener() {
    243                     @Override
    244                     public void onClick(DialogInterface dialog, int which, boolean isChecked) {
    245                         mSetValues[which] = isChecked;
    246                     }
    247         });
    248     }
    249 
    250     @Override
    251     protected void onDialogClosed(boolean positiveResult) {
    252         super.onDialogClosed(positiveResult);
    253 
    254         if (positiveResult) {
    255             if (callChangeListener(getValues())) {
    256                 return;
    257             }
    258         }
    259         System.arraycopy(mOrigValues, 0, mSetValues, 0, mSetValues.length);
    260     }
    261 
    262     @Override
    263     protected Object onGetDefaultValue(TypedArray a, int index) {
    264         return a.getString(index);
    265     }
    266 
    267     @Override
    268     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
    269     }
    270 
    271     @Override
    272     protected Parcelable onSaveInstanceState() {
    273         final Parcelable superState = super.onSaveInstanceState();
    274         if (isPersistent()) {
    275             // No need to save instance state since it's persistent
    276             return superState;
    277         }
    278 
    279         final SavedState myState = new SavedState(superState);
    280         myState.values = getValues();
    281         return myState;
    282     }
    283 
    284     @Override
    285     protected void onRestoreInstanceState(Parcelable state) {
    286         if (state == null || !state.getClass().equals(SavedState.class)) {
    287             // Didn't save state for us in onSaveInstanceState
    288             super.onRestoreInstanceState(state);
    289             return;
    290         }
    291 
    292         SavedState myState = (SavedState) state;
    293         super.onRestoreInstanceState(myState.getSuperState());
    294         setValues(myState.values);
    295     }
    296 
    297     private static class SavedState extends BaseSavedState {
    298         boolean[] values;
    299 
    300         public SavedState(Parcel source) {
    301             super(source);
    302             values = source.createBooleanArray();
    303         }
    304 
    305         @Override
    306         public void writeToParcel(Parcel dest, int flags) {
    307             super.writeToParcel(dest, flags);
    308             dest.writeBooleanArray(values);
    309         }
    310 
    311         public SavedState(Parcelable superState) {
    312             super(superState);
    313         }
    314 
    315         public static final Parcelable.Creator<SavedState> CREATOR =
    316                 new Parcelable.Creator<SavedState>() {
    317             public SavedState createFromParcel(Parcel in) {
    318                 return new SavedState(in);
    319             }
    320 
    321             public SavedState[] newArray(int size) {
    322                 return new SavedState[size];
    323             }
    324         };
    325     }
    326 
    327 }
    328