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