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