Home | History | Annotate | Download | only in preference
      1 /*
      2  * Copyright (C) 2010 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.content.Context;
     20 import android.content.SharedPreferences;
     21 import android.content.res.TypedArray;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 import android.text.TextUtils;
     25 import android.util.AttributeSet;
     26 import android.view.View;
     27 import android.widget.TextView;
     28 
     29 /**
     30  * Common base class for preferences that have two selectable states, persist a
     31  * boolean value in SharedPreferences, and may have dependent preferences that are
     32  * enabled/disabled based on the current state.
     33  */
     34 public abstract class TwoStatePreference extends Preference {
     35 
     36     private CharSequence mSummaryOn;
     37     private CharSequence mSummaryOff;
     38     boolean mChecked;
     39     private boolean mCheckedSet;
     40     private boolean mDisableDependentsState;
     41 
     42     public TwoStatePreference(
     43             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     44         super(context, attrs, defStyleAttr, defStyleRes);
     45     }
     46 
     47     public TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr) {
     48         this(context, attrs, defStyleAttr, 0);
     49     }
     50 
     51     public TwoStatePreference(Context context, AttributeSet attrs) {
     52         this(context, attrs, 0);
     53     }
     54 
     55     public TwoStatePreference(Context context) {
     56         this(context, null);
     57     }
     58 
     59     @Override
     60     protected void onClick() {
     61         super.onClick();
     62 
     63         final boolean newValue = !isChecked();
     64         if (callChangeListener(newValue)) {
     65             setChecked(newValue);
     66         }
     67     }
     68 
     69     /**
     70      * Sets the checked state and saves it to the {@link SharedPreferences}.
     71      *
     72      * @param checked The checked state.
     73      */
     74     public void setChecked(boolean checked) {
     75         // Always persist/notify the first time; don't assume the field's default of false.
     76         final boolean changed = mChecked != checked;
     77         if (changed || !mCheckedSet) {
     78             mChecked = checked;
     79             mCheckedSet = true;
     80             persistBoolean(checked);
     81             if (changed) {
     82                 notifyDependencyChange(shouldDisableDependents());
     83                 notifyChanged();
     84             }
     85         }
     86     }
     87 
     88     /**
     89      * Returns the checked state.
     90      *
     91      * @return The checked state.
     92      */
     93     public boolean isChecked() {
     94         return mChecked;
     95     }
     96 
     97     @Override
     98     public boolean shouldDisableDependents() {
     99         boolean shouldDisable = mDisableDependentsState ? mChecked : !mChecked;
    100         return shouldDisable || super.shouldDisableDependents();
    101     }
    102 
    103     /**
    104      * Sets the summary to be shown when checked.
    105      *
    106      * @param summary The summary to be shown when checked.
    107      */
    108     public void setSummaryOn(CharSequence summary) {
    109         mSummaryOn = summary;
    110         if (isChecked()) {
    111             notifyChanged();
    112         }
    113     }
    114 
    115     /**
    116      * @see #setSummaryOn(CharSequence)
    117      * @param summaryResId The summary as a resource.
    118      */
    119     public void setSummaryOn(int summaryResId) {
    120         setSummaryOn(getContext().getString(summaryResId));
    121     }
    122 
    123     /**
    124      * Returns the summary to be shown when checked.
    125      * @return The summary.
    126      */
    127     public CharSequence getSummaryOn() {
    128         return mSummaryOn;
    129     }
    130 
    131     /**
    132      * Sets the summary to be shown when unchecked.
    133      *
    134      * @param summary The summary to be shown when unchecked.
    135      */
    136     public void setSummaryOff(CharSequence summary) {
    137         mSummaryOff = summary;
    138         if (!isChecked()) {
    139             notifyChanged();
    140         }
    141     }
    142 
    143     /**
    144      * @see #setSummaryOff(CharSequence)
    145      * @param summaryResId The summary as a resource.
    146      */
    147     public void setSummaryOff(int summaryResId) {
    148         setSummaryOff(getContext().getString(summaryResId));
    149     }
    150 
    151     /**
    152      * Returns the summary to be shown when unchecked.
    153      * @return The summary.
    154      */
    155     public CharSequence getSummaryOff() {
    156         return mSummaryOff;
    157     }
    158 
    159     /**
    160      * Returns whether dependents are disabled when this preference is on ({@code true})
    161      * or when this preference is off ({@code false}).
    162      *
    163      * @return Whether dependents are disabled when this preference is on ({@code true})
    164      *         or when this preference is off ({@code false}).
    165      */
    166     public boolean getDisableDependentsState() {
    167         return mDisableDependentsState;
    168     }
    169 
    170     /**
    171      * Sets whether dependents are disabled when this preference is on ({@code true})
    172      * or when this preference is off ({@code false}).
    173      *
    174      * @param disableDependentsState The preference state that should disable dependents.
    175      */
    176     public void setDisableDependentsState(boolean disableDependentsState) {
    177         mDisableDependentsState = disableDependentsState;
    178     }
    179 
    180     @Override
    181     protected Object onGetDefaultValue(TypedArray a, int index) {
    182         return a.getBoolean(index, false);
    183     }
    184 
    185     @Override
    186     protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
    187         setChecked(restoreValue ? getPersistedBoolean(mChecked)
    188                 : (Boolean) defaultValue);
    189     }
    190 
    191     /**
    192      * Sync a summary view contained within view's subhierarchy with the correct summary text.
    193      * @param view View where a summary should be located
    194      */
    195     void syncSummaryView(View view) {
    196         // Sync the summary view
    197         TextView summaryView = (TextView) view.findViewById(com.android.internal.R.id.summary);
    198         if (summaryView != null) {
    199             boolean useDefaultSummary = true;
    200             if (mChecked && !TextUtils.isEmpty(mSummaryOn)) {
    201                 summaryView.setText(mSummaryOn);
    202                 useDefaultSummary = false;
    203             } else if (!mChecked && !TextUtils.isEmpty(mSummaryOff)) {
    204                 summaryView.setText(mSummaryOff);
    205                 useDefaultSummary = false;
    206             }
    207 
    208             if (useDefaultSummary) {
    209                 final CharSequence summary = getSummary();
    210                 if (!TextUtils.isEmpty(summary)) {
    211                     summaryView.setText(summary);
    212                     useDefaultSummary = false;
    213                 }
    214             }
    215 
    216             int newVisibility = View.GONE;
    217             if (!useDefaultSummary) {
    218                 // Someone has written to it
    219                 newVisibility = View.VISIBLE;
    220             }
    221             if (newVisibility != summaryView.getVisibility()) {
    222                 summaryView.setVisibility(newVisibility);
    223             }
    224         }
    225     }
    226 
    227     @Override
    228     protected Parcelable onSaveInstanceState() {
    229         final Parcelable superState = super.onSaveInstanceState();
    230         if (isPersistent()) {
    231             // No need to save instance state since it's persistent
    232             return superState;
    233         }
    234 
    235         final SavedState myState = new SavedState(superState);
    236         myState.checked = isChecked();
    237         return myState;
    238     }
    239 
    240     @Override
    241     protected void onRestoreInstanceState(Parcelable state) {
    242         if (state == null || !state.getClass().equals(SavedState.class)) {
    243             // Didn't save state for us in onSaveInstanceState
    244             super.onRestoreInstanceState(state);
    245             return;
    246         }
    247 
    248         SavedState myState = (SavedState) state;
    249         super.onRestoreInstanceState(myState.getSuperState());
    250         setChecked(myState.checked);
    251     }
    252 
    253     static class SavedState extends BaseSavedState {
    254         boolean checked;
    255 
    256         public SavedState(Parcel source) {
    257             super(source);
    258             checked = source.readInt() == 1;
    259         }
    260 
    261         @Override
    262         public void writeToParcel(Parcel dest, int flags) {
    263             super.writeToParcel(dest, flags);
    264             dest.writeInt(checked ? 1 : 0);
    265         }
    266 
    267         public SavedState(Parcelable superState) {
    268             super(superState);
    269         }
    270 
    271         public static final Parcelable.Creator<SavedState> CREATOR =
    272                 new Parcelable.Creator<SavedState>() {
    273             public SavedState createFromParcel(Parcel in) {
    274                 return new SavedState(in);
    275             }
    276 
    277             public SavedState[] newArray(int size) {
    278                 return new SavedState[size];
    279             }
    280         };
    281     }
    282 }
    283