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 TwoStatePreference( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)42 public TwoStatePreference( 43 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 44 super(context, attrs, defStyleAttr, defStyleRes); 45 } 46 TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr)47 public TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr) { 48 this(context, attrs, defStyleAttr, 0); 49 } 50 TwoStatePreference(Context context, AttributeSet attrs)51 public TwoStatePreference(Context context, AttributeSet attrs) { 52 this(context, attrs, 0); 53 } 54 TwoStatePreference(Context context)55 public TwoStatePreference(Context context) { 56 this(context, null); 57 } 58 59 @Override onClick()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 */ setChecked(boolean checked)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 */ isChecked()93 public boolean isChecked() { 94 return mChecked; 95 } 96 97 @Override shouldDisableDependents()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 */ setSummaryOn(CharSequence summary)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 */ setSummaryOn(int summaryResId)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 */ getSummaryOn()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 */ setSummaryOff(CharSequence summary)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 */ setSummaryOff(int summaryResId)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 */ getSummaryOff()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 */ getDisableDependentsState()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 */ setDisableDependentsState(boolean disableDependentsState)176 public void setDisableDependentsState(boolean disableDependentsState) { 177 mDisableDependentsState = disableDependentsState; 178 } 179 180 @Override onGetDefaultValue(TypedArray a, int index)181 protected Object onGetDefaultValue(TypedArray a, int index) { 182 return a.getBoolean(index, false); 183 } 184 185 @Override onSetInitialValue(boolean restoreValue, Object defaultValue)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 */ syncSummaryView(View view)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 onSaveInstanceState()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 onRestoreInstanceState(Parcelable state)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 SavedState(Parcel source)256 public SavedState(Parcel source) { 257 super(source); 258 checked = source.readInt() == 1; 259 } 260 261 @Override writeToParcel(Parcel dest, int flags)262 public void writeToParcel(Parcel dest, int flags) { 263 super.writeToParcel(dest, flags); 264 dest.writeInt(checked ? 1 : 0); 265 } 266 SavedState(Parcelable superState)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