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