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