Home | History | Annotate | Download | only in preference
      1 /*
      2  * Copyright (C) 2007 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 
     20 import android.app.AlertDialog.Builder;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.res.TypedArray;
     24 import android.os.Parcel;
     25 import android.os.Parcelable;
     26 import android.util.AttributeSet;
     27 
     28 /**
     29  * A {@link Preference} that displays a list of entries as
     30  * a dialog.
     31  * <p>
     32  * This preference will store a string into the SharedPreferences. This string will be the value
     33  * from the {@link #setEntryValues(CharSequence[])} array.
     34  *
     35  * @attr ref android.R.styleable#ListPreference_entries
     36  * @attr ref android.R.styleable#ListPreference_entryValues
     37  */
     38 public class ListPreference extends DialogPreference {
     39     private CharSequence[] mEntries;
     40     private CharSequence[] mEntryValues;
     41     private String mValue;
     42     private int mClickedDialogEntryIndex;
     43 
     44     public ListPreference(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         mEntryValues = a.getTextArray(com.android.internal.R.styleable.ListPreference_entryValues);
     51         a.recycle();
     52     }
     53 
     54     public ListPreference(Context context) {
     55         this(context, null);
     56     }
     57 
     58     /**
     59      * Sets the human-readable entries to be shown in the list. This will be
     60      * shown in subsequent dialogs.
     61      * <p>
     62      * Each entry must have a corresponding index in
     63      * {@link #setEntryValues(CharSequence[])}.
     64      *
     65      * @param entries The entries.
     66      * @see #setEntryValues(CharSequence[])
     67      */
     68     public void setEntries(CharSequence[] entries) {
     69         mEntries = entries;
     70     }
     71 
     72     /**
     73      * @see #setEntries(CharSequence[])
     74      * @param entriesResId The entries array as a resource.
     75      */
     76     public void setEntries(int entriesResId) {
     77         setEntries(getContext().getResources().getTextArray(entriesResId));
     78     }
     79 
     80     /**
     81      * The list of entries to be shown in the list in subsequent dialogs.
     82      *
     83      * @return The list as an array.
     84      */
     85     public CharSequence[] getEntries() {
     86         return mEntries;
     87     }
     88 
     89     /**
     90      * The array to find the value to save for a preference when an entry from
     91      * entries is selected. If a user clicks on the second item in entries, the
     92      * second item in this array will be saved to the preference.
     93      *
     94      * @param entryValues The array to be used as values to save for the preference.
     95      */
     96     public void setEntryValues(CharSequence[] entryValues) {
     97         mEntryValues = entryValues;
     98     }
     99 
    100     /**
    101      * @see #setEntryValues(CharSequence[])
    102      * @param entryValuesResId The entry values array as a resource.
    103      */
    104     public void setEntryValues(int entryValuesResId) {
    105         setEntryValues(getContext().getResources().getTextArray(entryValuesResId));
    106     }
    107 
    108     /**
    109      * Returns the array of values to be saved for the preference.
    110      *
    111      * @return The array of values.
    112      */
    113     public CharSequence[] getEntryValues() {
    114         return mEntryValues;
    115     }
    116 
    117     /**
    118      * Sets the value of the key. This should be one of the entries in
    119      * {@link #getEntryValues()}.
    120      *
    121      * @param value The value to set for the key.
    122      */
    123     public void setValue(String value) {
    124         mValue = value;
    125 
    126         persistString(value);
    127     }
    128 
    129     /**
    130      * Sets the value to the given index from the entry values.
    131      *
    132      * @param index The index of the value to set.
    133      */
    134     public void setValueIndex(int index) {
    135         if (mEntryValues != null) {
    136             setValue(mEntryValues[index].toString());
    137         }
    138     }
    139 
    140     /**
    141      * Returns the value of the key. This should be one of the entries in
    142      * {@link #getEntryValues()}.
    143      *
    144      * @return The value of the key.
    145      */
    146     public String getValue() {
    147         return mValue;
    148     }
    149 
    150     /**
    151      * Returns the entry corresponding to the current value.
    152      *
    153      * @return The entry corresponding to the current value, or null.
    154      */
    155     public CharSequence getEntry() {
    156         int index = getValueIndex();
    157         return index >= 0 && mEntries != null ? mEntries[index] : null;
    158     }
    159 
    160     /**
    161      * Returns the index of the given value (in the entry values array).
    162      *
    163      * @param value The value whose index should be returned.
    164      * @return The index of the value, or -1 if not found.
    165      */
    166     public int findIndexOfValue(String value) {
    167         if (value != null && mEntryValues != null) {
    168             for (int i = mEntryValues.length - 1; i >= 0; i--) {
    169                 if (mEntryValues[i].equals(value)) {
    170                     return i;
    171                 }
    172             }
    173         }
    174         return -1;
    175     }
    176 
    177     private int getValueIndex() {
    178         return findIndexOfValue(mValue);
    179     }
    180 
    181     @Override
    182     protected void onPrepareDialogBuilder(Builder builder) {
    183         super.onPrepareDialogBuilder(builder);
    184 
    185         if (mEntries == null || mEntryValues == null) {
    186             throw new IllegalStateException(
    187                     "ListPreference requires an entries array and an entryValues array.");
    188         }
    189 
    190         mClickedDialogEntryIndex = getValueIndex();
    191         builder.setSingleChoiceItems(mEntries, mClickedDialogEntryIndex,
    192                 new DialogInterface.OnClickListener() {
    193                     public void onClick(DialogInterface dialog, int which) {
    194                         mClickedDialogEntryIndex = which;
    195 
    196                         /*
    197                          * Clicking on an item simulates the positive button
    198                          * click, and dismisses the dialog.
    199                          */
    200                         ListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
    201                         dialog.dismiss();
    202                     }
    203         });
    204 
    205         /*
    206          * The typical interaction for list-based dialogs is to have
    207          * click-on-an-item dismiss the dialog instead of the user having to
    208          * press 'Ok'.
    209          */
    210         builder.setPositiveButton(null, null);
    211     }
    212 
    213     @Override
    214     protected void onDialogClosed(boolean positiveResult) {
    215         super.onDialogClosed(positiveResult);
    216 
    217         if (positiveResult && mClickedDialogEntryIndex >= 0 && mEntryValues != null) {
    218             String value = mEntryValues[mClickedDialogEntryIndex].toString();
    219             if (callChangeListener(value)) {
    220                 setValue(value);
    221             }
    222         }
    223     }
    224 
    225     @Override
    226     protected Object onGetDefaultValue(TypedArray a, int index) {
    227         return a.getString(index);
    228     }
    229 
    230     @Override
    231     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
    232         setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
    233     }
    234 
    235     @Override
    236     protected Parcelable onSaveInstanceState() {
    237         final Parcelable superState = super.onSaveInstanceState();
    238         if (isPersistent()) {
    239             // No need to save instance state since it's persistent
    240             return superState;
    241         }
    242 
    243         final SavedState myState = new SavedState(superState);
    244         myState.value = getValue();
    245         return myState;
    246     }
    247 
    248     @Override
    249     protected void onRestoreInstanceState(Parcelable state) {
    250         if (state == null || !state.getClass().equals(SavedState.class)) {
    251             // Didn't save state for us in onSaveInstanceState
    252             super.onRestoreInstanceState(state);
    253             return;
    254         }
    255 
    256         SavedState myState = (SavedState) state;
    257         super.onRestoreInstanceState(myState.getSuperState());
    258         setValue(myState.value);
    259     }
    260 
    261     private static class SavedState extends BaseSavedState {
    262         String value;
    263 
    264         public SavedState(Parcel source) {
    265             super(source);
    266             value = source.readString();
    267         }
    268 
    269         @Override
    270         public void writeToParcel(Parcel dest, int flags) {
    271             super.writeToParcel(dest, flags);
    272             dest.writeString(value);
    273         }
    274 
    275         public SavedState(Parcelable superState) {
    276             super(superState);
    277         }
    278 
    279         public static final Parcelable.Creator<SavedState> CREATOR =
    280                 new Parcelable.Creator<SavedState>() {
    281             public SavedState createFromParcel(Parcel in) {
    282                 return new SavedState(in);
    283             }
    284 
    285             public SavedState[] newArray(int size) {
    286                 return new SavedState[size];
    287             }
    288         };
    289     }
    290 
    291 }
    292