TwoStatePreference.java revision 5c3ea06a7a5558509545450ccc465d695bd1a2e6
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.util.AttributeSet; 25import android.view.View; 26import android.view.accessibility.AccessibilityEvent; 27import android.view.accessibility.AccessibilityManager; 28import 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 */ 35public abstract class TwoStatePreference extends Preference { 36 37 private CharSequence mSummaryOn; 38 private CharSequence mSummaryOff; 39 boolean mChecked; 40 private boolean mSendAccessibilityEventViewClickedType; 41 private boolean mDisableDependentsState; 42 43 private SendAccessibilityEventTypeViewClicked mSendAccessibilityEventTypeViewClicked; 44 45 public TwoStatePreference(Context context, AttributeSet attrs, int defStyle) { 46 super(context, attrs, defStyle); 47 } 48 49 public TwoStatePreference(Context context, AttributeSet attrs) { 50 this(context, attrs, 0); 51 } 52 53 public TwoStatePreference(Context context) { 54 this(context, null); 55 } 56 57 @Override 58 protected void onClick() { 59 super.onClick(); 60 61 boolean newValue = !isChecked(); 62 63 // in onBindView() an AccessibilityEventViewClickedType is sent to announce the change 64 // not sending 65 mSendAccessibilityEventViewClickedType = true; 66 67 if (!callChangeListener(newValue)) { 68 return; 69 } 70 71 setChecked(newValue); 72 } 73 74 /** 75 * Sets the checked state and saves it to the {@link SharedPreferences}. 76 * 77 * @param checked The checked state. 78 */ 79 public void setChecked(boolean checked) { 80 if (mChecked != checked) { 81 mChecked = checked; 82 persistBoolean(checked); 83 notifyDependencyChange(shouldDisableDependents()); 84 notifyChanged(); 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 * Post send an accessibility event for the given view if appropriate. 193 * 194 * @param view View that should send the event 195 */ 196 void postSendAccessibilityEventForView(View view) { 197 // send an event to announce the value change of the state. It is done here 198 // because clicking a preference does not immediately change the checked state 199 // for example when enabling the WiFi 200 if (mSendAccessibilityEventViewClickedType 201 && AccessibilityManager.getInstance(getContext()).isEnabled() 202 && view.isEnabled()) { 203 mSendAccessibilityEventViewClickedType = false; 204 if (mSendAccessibilityEventTypeViewClicked == null) { 205 mSendAccessibilityEventTypeViewClicked = new SendAccessibilityEventTypeViewClicked(); 206 } 207 mSendAccessibilityEventTypeViewClicked.mView = view; 208 view.post(mSendAccessibilityEventTypeViewClicked); 209 } 210 } 211 212 /** 213 * Sync a summary view contained within view's subhierarchy with the correct summary text. 214 * @param view View where a summary should be located 215 */ 216 void syncSummaryView(View view) { 217 // Sync the summary view 218 TextView summaryView = (TextView) view.findViewById(com.android.internal.R.id.summary); 219 if (summaryView != null) { 220 boolean useDefaultSummary = true; 221 if (mChecked && mSummaryOn != null) { 222 summaryView.setText(mSummaryOn); 223 useDefaultSummary = false; 224 } else if (!mChecked && mSummaryOff != null) { 225 summaryView.setText(mSummaryOff); 226 useDefaultSummary = false; 227 } 228 229 if (useDefaultSummary) { 230 final CharSequence summary = getSummary(); 231 if (summary != null) { 232 summaryView.setText(summary); 233 useDefaultSummary = false; 234 } 235 } 236 237 int newVisibility = View.GONE; 238 if (!useDefaultSummary) { 239 // Someone has written to it 240 newVisibility = View.VISIBLE; 241 } 242 if (newVisibility != summaryView.getVisibility()) { 243 summaryView.setVisibility(newVisibility); 244 } 245 } 246 } 247 248 @Override 249 protected Parcelable onSaveInstanceState() { 250 final Parcelable superState = super.onSaveInstanceState(); 251 if (isPersistent()) { 252 // No need to save instance state since it's persistent 253 return superState; 254 } 255 256 final SavedState myState = new SavedState(superState); 257 myState.checked = isChecked(); 258 return myState; 259 } 260 261 @Override 262 protected void onRestoreInstanceState(Parcelable state) { 263 if (state == null || !state.getClass().equals(SavedState.class)) { 264 // Didn't save state for us in onSaveInstanceState 265 super.onRestoreInstanceState(state); 266 return; 267 } 268 269 SavedState myState = (SavedState) state; 270 super.onRestoreInstanceState(myState.getSuperState()); 271 setChecked(myState.checked); 272 } 273 274 static class SavedState extends BaseSavedState { 275 boolean checked; 276 277 public SavedState(Parcel source) { 278 super(source); 279 checked = source.readInt() == 1; 280 } 281 282 @Override 283 public void writeToParcel(Parcel dest, int flags) { 284 super.writeToParcel(dest, flags); 285 dest.writeInt(checked ? 1 : 0); 286 } 287 288 public SavedState(Parcelable superState) { 289 super(superState); 290 } 291 292 public static final Parcelable.Creator<SavedState> CREATOR = 293 new Parcelable.Creator<SavedState>() { 294 public SavedState createFromParcel(Parcel in) { 295 return new SavedState(in); 296 } 297 298 public SavedState[] newArray(int size) { 299 return new SavedState[size]; 300 } 301 }; 302 } 303 304 private final class SendAccessibilityEventTypeViewClicked implements Runnable { 305 private View mView; 306 307 @Override 308 public void run() { 309 mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 310 } 311 } 312} 313