blob: af839533404560f9ea811956af57f8e58b7c4503 [file] [log] [blame]
Adam Powellbe0a4532010-11-29 17:47:48 -08001/*
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
Adam Powellbe0a4532010-11-29 17:47:48 -080019import android.content.Context;
20import android.content.SharedPreferences;
21import android.content.res.TypedArray;
22import android.os.Parcel;
23import android.os.Parcelable;
Amith Yamasanib2515882013-09-09 14:46:07 -070024import android.text.TextUtils;
Adam Powellbe0a4532010-11-29 17:47:48 -080025import 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;
Adam Powellc1b07212012-08-10 14:20:14 -070041 private boolean mCheckedSet;
Svetoslav Ganov76502592011-07-29 10:44:59 -070042 private boolean mSendClickAccessibilityEvent;
Adam Powellbe0a4532010-11-29 17:47:48 -080043 private boolean mDisableDependentsState;
44
Svetoslav Ganov5c3ea062011-07-22 18:52:56 -070045
Adam Powellbe0a4532010-11-29 17:47:48 -080046 public TwoStatePreference(Context context, AttributeSet attrs, int defStyle) {
47 super(context, attrs, defStyle);
Adam Powellbe0a4532010-11-29 17:47:48 -080048 }
49
50 public TwoStatePreference(Context context, AttributeSet attrs) {
Svetoslav Ganov5c3ea062011-07-22 18:52:56 -070051 this(context, attrs, 0);
Adam Powellbe0a4532010-11-29 17:47:48 -080052 }
53
54 public TwoStatePreference(Context context) {
Svetoslav Ganov5c3ea062011-07-22 18:52:56 -070055 this(context, null);
Adam Powellbe0a4532010-11-29 17:47:48 -080056 }
57
58 @Override
59 protected void onClick() {
60 super.onClick();
61
62 boolean newValue = !isChecked();
63
Svetoslav Ganov76502592011-07-29 10:44:59 -070064 mSendClickAccessibilityEvent = true;
Adam Powellbe0a4532010-11-29 17:47:48 -080065
66 if (!callChangeListener(newValue)) {
67 return;
68 }
69
70 setChecked(newValue);
71 }
72
73 /**
74 * Sets the checked state and saves it to the {@link SharedPreferences}.
75 *
76 * @param checked The checked state.
77 */
78 public void setChecked(boolean checked) {
Adam Powellc1b07212012-08-10 14:20:14 -070079 // Always persist/notify the first time; don't assume the field's default of false.
80 final boolean changed = mChecked != checked;
81 if (changed || !mCheckedSet) {
Adam Powellbe0a4532010-11-29 17:47:48 -080082 mChecked = checked;
Adam Powellc1b07212012-08-10 14:20:14 -070083 mCheckedSet = true;
Adam Powellbe0a4532010-11-29 17:47:48 -080084 persistBoolean(checked);
Adam Powellc1b07212012-08-10 14:20:14 -070085 if (changed) {
86 notifyDependencyChange(shouldDisableDependents());
87 notifyChanged();
88 }
Adam Powellbe0a4532010-11-29 17:47:48 -080089 }
90 }
91
92 /**
93 * Returns the checked state.
94 *
95 * @return The checked state.
96 */
97 public boolean isChecked() {
98 return mChecked;
99 }
100
101 @Override
102 public boolean shouldDisableDependents() {
103 boolean shouldDisable = mDisableDependentsState ? mChecked : !mChecked;
104 return shouldDisable || super.shouldDisableDependents();
105 }
106
107 /**
108 * Sets the summary to be shown when checked.
109 *
110 * @param summary The summary to be shown when checked.
111 */
112 public void setSummaryOn(CharSequence summary) {
113 mSummaryOn = summary;
114 if (isChecked()) {
115 notifyChanged();
116 }
117 }
118
119 /**
120 * @see #setSummaryOn(CharSequence)
121 * @param summaryResId The summary as a resource.
122 */
123 public void setSummaryOn(int summaryResId) {
124 setSummaryOn(getContext().getString(summaryResId));
125 }
126
127 /**
128 * Returns the summary to be shown when checked.
129 * @return The summary.
130 */
131 public CharSequence getSummaryOn() {
132 return mSummaryOn;
133 }
134
135 /**
136 * Sets the summary to be shown when unchecked.
137 *
138 * @param summary The summary to be shown when unchecked.
139 */
140 public void setSummaryOff(CharSequence summary) {
141 mSummaryOff = summary;
142 if (!isChecked()) {
143 notifyChanged();
144 }
145 }
146
147 /**
148 * @see #setSummaryOff(CharSequence)
149 * @param summaryResId The summary as a resource.
150 */
151 public void setSummaryOff(int summaryResId) {
152 setSummaryOff(getContext().getString(summaryResId));
153 }
154
155 /**
156 * Returns the summary to be shown when unchecked.
157 * @return The summary.
158 */
159 public CharSequence getSummaryOff() {
160 return mSummaryOff;
161 }
162
163 /**
164 * Returns whether dependents are disabled when this preference is on ({@code true})
165 * or when this preference is off ({@code false}).
166 *
167 * @return Whether dependents are disabled when this preference is on ({@code true})
168 * or when this preference is off ({@code false}).
169 */
170 public boolean getDisableDependentsState() {
171 return mDisableDependentsState;
172 }
173
174 /**
175 * Sets whether dependents are disabled when this preference is on ({@code true})
176 * or when this preference is off ({@code false}).
177 *
178 * @param disableDependentsState The preference state that should disable dependents.
179 */
180 public void setDisableDependentsState(boolean disableDependentsState) {
181 mDisableDependentsState = disableDependentsState;
182 }
183
184 @Override
185 protected Object onGetDefaultValue(TypedArray a, int index) {
186 return a.getBoolean(index, false);
187 }
188
189 @Override
190 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
191 setChecked(restoreValue ? getPersistedBoolean(mChecked)
192 : (Boolean) defaultValue);
193 }
194
Svetoslav Ganov76502592011-07-29 10:44:59 -0700195 void sendAccessibilityEvent(View view) {
196 // Since the view is still not attached we create, populate,
197 // and send the event directly since we do not know when it
198 // will be attached and posting commands is not as clean.
199 AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getContext());
200 if (mSendClickAccessibilityEvent && accessibilityManager.isEnabled()) {
201 AccessibilityEvent event = AccessibilityEvent.obtain();
202 event.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
203 view.onInitializeAccessibilityEvent(event);
204 view.dispatchPopulateAccessibilityEvent(event);
205 accessibilityManager.sendAccessibilityEvent(event);
Adam Powellbe0a4532010-11-29 17:47:48 -0800206 }
Svetoslav Ganov76502592011-07-29 10:44:59 -0700207 mSendClickAccessibilityEvent = false;
Adam Powellbe0a4532010-11-29 17:47:48 -0800208 }
209
210 /**
211 * Sync a summary view contained within view's subhierarchy with the correct summary text.
212 * @param view View where a summary should be located
213 */
214 void syncSummaryView(View view) {
215 // Sync the summary view
216 TextView summaryView = (TextView) view.findViewById(com.android.internal.R.id.summary);
217 if (summaryView != null) {
218 boolean useDefaultSummary = true;
Amith Yamasanib2515882013-09-09 14:46:07 -0700219 if (mChecked && !TextUtils.isEmpty(mSummaryOn)) {
Adam Powellbe0a4532010-11-29 17:47:48 -0800220 summaryView.setText(mSummaryOn);
221 useDefaultSummary = false;
Amith Yamasanib2515882013-09-09 14:46:07 -0700222 } else if (!mChecked && !TextUtils.isEmpty(mSummaryOff)) {
Adam Powellbe0a4532010-11-29 17:47:48 -0800223 summaryView.setText(mSummaryOff);
224 useDefaultSummary = false;
225 }
226
227 if (useDefaultSummary) {
228 final CharSequence summary = getSummary();
Amith Yamasanib2515882013-09-09 14:46:07 -0700229 if (!TextUtils.isEmpty(summary)) {
Adam Powellbe0a4532010-11-29 17:47:48 -0800230 summaryView.setText(summary);
231 useDefaultSummary = false;
232 }
233 }
234
235 int newVisibility = View.GONE;
236 if (!useDefaultSummary) {
237 // Someone has written to it
238 newVisibility = View.VISIBLE;
239 }
240 if (newVisibility != summaryView.getVisibility()) {
241 summaryView.setVisibility(newVisibility);
242 }
243 }
244 }
245
246 @Override
247 protected Parcelable onSaveInstanceState() {
248 final Parcelable superState = super.onSaveInstanceState();
249 if (isPersistent()) {
250 // No need to save instance state since it's persistent
251 return superState;
252 }
253
254 final SavedState myState = new SavedState(superState);
255 myState.checked = isChecked();
256 return myState;
257 }
258
259 @Override
260 protected void onRestoreInstanceState(Parcelable state) {
261 if (state == null || !state.getClass().equals(SavedState.class)) {
262 // Didn't save state for us in onSaveInstanceState
263 super.onRestoreInstanceState(state);
264 return;
265 }
266
267 SavedState myState = (SavedState) state;
268 super.onRestoreInstanceState(myState.getSuperState());
269 setChecked(myState.checked);
270 }
271
272 static class SavedState extends BaseSavedState {
273 boolean checked;
274
275 public SavedState(Parcel source) {
276 super(source);
277 checked = source.readInt() == 1;
278 }
279
280 @Override
281 public void writeToParcel(Parcel dest, int flags) {
282 super.writeToParcel(dest, flags);
283 dest.writeInt(checked ? 1 : 0);
284 }
285
286 public SavedState(Parcelable superState) {
287 super(superState);
288 }
289
290 public static final Parcelable.Creator<SavedState> CREATOR =
291 new Parcelable.Creator<SavedState>() {
292 public SavedState createFromParcel(Parcel in) {
293 return new SavedState(in);
294 }
295
296 public SavedState[] newArray(int size) {
297 return new SavedState[size];
298 }
299 };
300 }
Adam Powellbe0a4532010-11-29 17:47:48 -0800301}