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