OSDN Git Service

Merge "add Toshiba usb driver link delete Fujitsu-Toshiba bug: 9755017" into jb-mr1...
[android-x86/frameworks-base.git] / core / java / android / preference / Preference.java
1 /*
2  * Copyright (C) 2007 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 com.android.internal.util.CharSequences;
20
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.SharedPreferences;
24 import android.content.res.TypedArray;
25 import android.graphics.drawable.Drawable;
26 import android.os.Bundle;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.text.TextUtils;
30 import android.util.AttributeSet;
31 import android.view.AbsSavedState;
32 import android.view.KeyEvent;
33 import android.view.LayoutInflater;
34 import android.view.View;
35 import android.view.ViewGroup;
36 import android.widget.ImageView;
37 import android.widget.ListView;
38 import android.widget.TextView;
39
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Set;
43
44 /**
45  * Represents the basic Preference UI building
46  * block displayed by a {@link PreferenceActivity} in the form of a
47  * {@link ListView}. This class provides the {@link View} to be displayed in
48  * the activity and associates with a {@link SharedPreferences} to
49  * store/retrieve the preference data.
50  * <p>
51  * When specifying a preference hierarchy in XML, each element can point to a
52  * subclass of {@link Preference}, similar to the view hierarchy and layouts.
53  * <p>
54  * This class contains a {@code key} that will be used as the key into the
55  * {@link SharedPreferences}. It is up to the subclass to decide how to store
56  * the value.
57  * 
58  * <div class="special reference">
59  * <h3>Developer Guides</h3>
60  * <p>For information about building a settings UI with Preferences,
61  * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
62  * guide.</p>
63  * </div>
64  * 
65  * @attr ref android.R.styleable#Preference_icon
66  * @attr ref android.R.styleable#Preference_key
67  * @attr ref android.R.styleable#Preference_title
68  * @attr ref android.R.styleable#Preference_summary
69  * @attr ref android.R.styleable#Preference_order
70  * @attr ref android.R.styleable#Preference_fragment
71  * @attr ref android.R.styleable#Preference_layout
72  * @attr ref android.R.styleable#Preference_widgetLayout
73  * @attr ref android.R.styleable#Preference_enabled
74  * @attr ref android.R.styleable#Preference_selectable
75  * @attr ref android.R.styleable#Preference_dependency
76  * @attr ref android.R.styleable#Preference_persistent
77  * @attr ref android.R.styleable#Preference_defaultValue
78  * @attr ref android.R.styleable#Preference_shouldDisableView
79  */
80 public class Preference implements Comparable<Preference>, OnDependencyChangeListener { 
81     /**
82      * Specify for {@link #setOrder(int)} if a specific order is not required.
83      */
84     public static final int DEFAULT_ORDER = Integer.MAX_VALUE;
85
86     private Context mContext;
87     private PreferenceManager mPreferenceManager;
88     
89     /**
90      * Set when added to hierarchy since we need a unique ID within that
91      * hierarchy.
92      */
93     private long mId;
94     
95     private OnPreferenceChangeListener mOnChangeListener;
96     private OnPreferenceClickListener mOnClickListener;
97
98     private int mOrder = DEFAULT_ORDER;
99     private CharSequence mTitle;
100     private int mTitleRes;
101     private CharSequence mSummary;
102     /**
103      * mIconResId is overridden by mIcon, if mIcon is specified.
104      */
105     private int mIconResId;
106     private Drawable mIcon;
107     private String mKey;
108     private Intent mIntent;
109     private String mFragment;
110     private Bundle mExtras;
111     private boolean mEnabled = true;
112     private boolean mSelectable = true;
113     private boolean mRequiresKey;
114     private boolean mPersistent = true;
115     private String mDependencyKey;
116     private Object mDefaultValue;
117     private boolean mDependencyMet = true;
118     
119     /**
120      * @see #setShouldDisableView(boolean)
121      */
122     private boolean mShouldDisableView = true;
123     
124     private int mLayoutResId = com.android.internal.R.layout.preference;
125     private int mWidgetLayoutResId;
126     private boolean mHasSpecifiedLayout = false;
127     
128     private OnPreferenceChangeInternalListener mListener;
129     
130     private List<Preference> mDependents;
131     
132     private boolean mBaseMethodCalled;
133     
134     /**
135      * Interface definition for a callback to be invoked when the value of this
136      * {@link Preference} has been changed by the user and is
137      * about to be set and/or persisted.  This gives the client a chance
138      * to prevent setting and/or persisting the value.
139      */
140     public interface OnPreferenceChangeListener {
141         /**
142          * Called when a Preference has been changed by the user. This is
143          * called before the state of the Preference is about to be updated and
144          * before the state is persisted.
145          * 
146          * @param preference The changed Preference.
147          * @param newValue The new value of the Preference.
148          * @return True to update the state of the Preference with the new value.
149          */
150         boolean onPreferenceChange(Preference preference, Object newValue);
151     }
152
153     /**
154      * Interface definition for a callback to be invoked when a {@link Preference} is
155      * clicked.
156      */
157     public interface OnPreferenceClickListener {
158         /**
159          * Called when a Preference has been clicked.
160          *
161          * @param preference The Preference that was clicked.
162          * @return True if the click was handled.
163          */
164         boolean onPreferenceClick(Preference preference);
165     }
166
167     /**
168      * Interface definition for a callback to be invoked when this
169      * {@link Preference} is changed or, if this is a group, there is an
170      * addition/removal of {@link Preference}(s). This is used internally.
171      */
172     interface OnPreferenceChangeInternalListener {
173         /**
174          * Called when this Preference has changed.
175          * 
176          * @param preference This preference.
177          */
178         void onPreferenceChange(Preference preference);
179         
180         /**
181          * Called when this group has added/removed {@link Preference}(s).
182          * 
183          * @param preference This Preference.
184          */
185         void onPreferenceHierarchyChange(Preference preference);
186     }
187
188     /**
189      * Perform inflation from XML and apply a class-specific base style. This
190      * constructor of Preference allows subclasses to use their own base
191      * style when they are inflating. For example, a {@link CheckBoxPreference}
192      * constructor calls this version of the super class constructor and
193      * supplies {@code android.R.attr.checkBoxPreferenceStyle} for <var>defStyle</var>.
194      * This allows the theme's checkbox preference style to modify all of the base
195      * preference attributes as well as the {@link CheckBoxPreference} class's
196      * attributes.
197      * 
198      * @param context The Context this is associated with, through which it can
199      *            access the current theme, resources, {@link SharedPreferences},
200      *            etc.
201      * @param attrs The attributes of the XML tag that is inflating the preference.
202      * @param defStyle The default style to apply to this preference. If 0, no style
203      *            will be applied (beyond what is included in the theme). This
204      *            may either be an attribute resource, whose value will be
205      *            retrieved from the current theme, or an explicit style
206      *            resource.
207      * @see #Preference(Context, AttributeSet)
208      */
209     public Preference(Context context, AttributeSet attrs, int defStyle) {
210         mContext = context;
211
212         TypedArray a = context.obtainStyledAttributes(attrs,
213                 com.android.internal.R.styleable.Preference, defStyle, 0);
214         for (int i = a.getIndexCount(); i >= 0; i--) {
215             int attr = a.getIndex(i); 
216             switch (attr) {
217                 case com.android.internal.R.styleable.Preference_icon:
218                     mIconResId = a.getResourceId(attr, 0);
219                     break;
220
221                 case com.android.internal.R.styleable.Preference_key:
222                     mKey = a.getString(attr);
223                     break;
224                     
225                 case com.android.internal.R.styleable.Preference_title:
226                     mTitleRes = a.getResourceId(attr, 0);
227                     mTitle = a.getString(attr);
228                     break;
229                     
230                 case com.android.internal.R.styleable.Preference_summary:
231                     mSummary = a.getString(attr);
232                     break;
233                     
234                 case com.android.internal.R.styleable.Preference_order:
235                     mOrder = a.getInt(attr, mOrder);
236                     break;
237
238                 case com.android.internal.R.styleable.Preference_fragment:
239                     mFragment = a.getString(attr);
240                     break;
241
242                 case com.android.internal.R.styleable.Preference_layout:
243                     mLayoutResId = a.getResourceId(attr, mLayoutResId);
244                     break;
245
246                 case com.android.internal.R.styleable.Preference_widgetLayout:
247                     mWidgetLayoutResId = a.getResourceId(attr, mWidgetLayoutResId);
248                     break;
249                     
250                 case com.android.internal.R.styleable.Preference_enabled:
251                     mEnabled = a.getBoolean(attr, true);
252                     break;
253                     
254                 case com.android.internal.R.styleable.Preference_selectable:
255                     mSelectable = a.getBoolean(attr, true);
256                     break;
257                     
258                 case com.android.internal.R.styleable.Preference_persistent:
259                     mPersistent = a.getBoolean(attr, mPersistent);
260                     break;
261                     
262                 case com.android.internal.R.styleable.Preference_dependency:
263                     mDependencyKey = a.getString(attr);
264                     break;
265                     
266                 case com.android.internal.R.styleable.Preference_defaultValue:
267                     mDefaultValue = onGetDefaultValue(a, attr);
268                     break;
269                     
270                 case com.android.internal.R.styleable.Preference_shouldDisableView:
271                     mShouldDisableView = a.getBoolean(attr, mShouldDisableView);
272                     break;
273             }
274         }
275         a.recycle();
276
277         if (!getClass().getName().startsWith("android.preference")) {
278             // For subclasses not in this package, assume the worst and don't cache views
279             mHasSpecifiedLayout = true;
280         }
281     }
282     
283     /**
284      * Constructor that is called when inflating a Preference from XML. This is
285      * called when a Preference is being constructed from an XML file, supplying
286      * attributes that were specified in the XML file. This version uses a
287      * default style of 0, so the only attribute values applied are those in the
288      * Context's Theme and the given AttributeSet.
289      * 
290      * @param context The Context this is associated with, through which it can
291      *            access the current theme, resources, {@link SharedPreferences},
292      *            etc.
293      * @param attrs The attributes of the XML tag that is inflating the
294      *            preference.
295      * @see #Preference(Context, AttributeSet, int)
296      */
297     public Preference(Context context, AttributeSet attrs) {
298         this(context, attrs, com.android.internal.R.attr.preferenceStyle);
299     }
300
301     /**
302      * Constructor to create a Preference.
303      * 
304      * @param context The Context in which to store Preference values.
305      */
306     public Preference(Context context) {
307         this(context, null);
308     }
309
310     /**
311      * Called when a Preference is being inflated and the default value
312      * attribute needs to be read. Since different Preference types have
313      * different value types, the subclass should get and return the default
314      * value which will be its value type.
315      * <p>
316      * For example, if the value type is String, the body of the method would
317      * proxy to {@link TypedArray#getString(int)}.
318      * 
319      * @param a The set of attributes.
320      * @param index The index of the default value attribute.
321      * @return The default value of this preference type.
322      */
323     protected Object onGetDefaultValue(TypedArray a, int index) {
324         return null;
325     }
326     
327     /**
328      * Sets an {@link Intent} to be used for
329      * {@link Context#startActivity(Intent)} when this Preference is clicked.
330      * 
331      * @param intent The intent associated with this Preference.
332      */
333     public void setIntent(Intent intent) {
334         mIntent = intent;
335     }
336     
337     /**
338      * Return the {@link Intent} associated with this Preference.
339      * 
340      * @return The {@link Intent} last set via {@link #setIntent(Intent)} or XML. 
341      */
342     public Intent getIntent() {
343         return mIntent;
344     }
345
346     /**
347      * Sets the class name of a fragment to be shown when this Preference is clicked.
348      *
349      * @param fragment The class name of the fragment associated with this Preference.
350      */
351     public void setFragment(String fragment) {
352         mFragment = fragment;
353     }
354
355     /**
356      * Return the fragment class name associated with this Preference.
357      *
358      * @return The fragment class name last set via {@link #setFragment} or XML.
359      */
360     public String getFragment() {
361         return mFragment;
362     }
363
364     /**
365      * Return the extras Bundle object associated with this preference, creating
366      * a new Bundle if there currently isn't one.  You can use this to get and
367      * set individual extra key/value pairs.
368      */
369     public Bundle getExtras() {
370         if (mExtras == null) {
371             mExtras = new Bundle();
372         }
373         return mExtras;
374     }
375
376     /**
377      * Return the extras Bundle object associated with this preference,
378      * returning null if there is not currently one.
379      */
380     public Bundle peekExtras() {
381         return mExtras;
382     }
383
384     /**
385      * Sets the layout resource that is inflated as the {@link View} to be shown
386      * for this Preference. In most cases, the default layout is sufficient for
387      * custom Preference objects and only the widget layout needs to be changed.
388      * <p>
389      * This layout should contain a {@link ViewGroup} with ID
390      * {@link android.R.id#widget_frame} to be the parent of the specific widget
391      * for this Preference. It should similarly contain
392      * {@link android.R.id#title} and {@link android.R.id#summary}.
393      * 
394      * @param layoutResId The layout resource ID to be inflated and returned as
395      *            a {@link View}.
396      * @see #setWidgetLayoutResource(int)
397      */
398     public void setLayoutResource(int layoutResId) {
399         if (layoutResId != mLayoutResId) {
400             // Layout changed
401             mHasSpecifiedLayout = true;
402         }
403
404         mLayoutResId = layoutResId;
405     }
406     
407     /**
408      * Gets the layout resource that will be shown as the {@link View} for this Preference.
409      * 
410      * @return The layout resource ID.
411      */
412     public int getLayoutResource() {
413         return mLayoutResId;
414     }
415     
416     /**
417      * Sets The layout for the controllable widget portion of this Preference. This
418      * is inflated into the main layout. For example, a {@link CheckBoxPreference}
419      * would specify a custom layout (consisting of just the CheckBox) here,
420      * instead of creating its own main layout.
421      * 
422      * @param widgetLayoutResId The layout resource ID to be inflated into the
423      *            main layout.
424      * @see #setLayoutResource(int)
425      */
426     public void setWidgetLayoutResource(int widgetLayoutResId) {
427         if (widgetLayoutResId != mWidgetLayoutResId) {
428             // Layout changed
429             mHasSpecifiedLayout = true;
430         }
431         mWidgetLayoutResId = widgetLayoutResId;
432     }
433
434     /**
435      * Gets the layout resource for the controllable widget portion of this Preference.
436      * 
437      * @return The layout resource ID.
438      */
439     public int getWidgetLayoutResource() {
440         return mWidgetLayoutResId;
441     }
442     
443     /**
444      * Gets the View that will be shown in the {@link PreferenceActivity}.
445      * 
446      * @param convertView The old View to reuse, if possible. Note: You should
447      *            check that this View is non-null and of an appropriate type
448      *            before using. If it is not possible to convert this View to
449      *            display the correct data, this method can create a new View.
450      * @param parent The parent that this View will eventually be attached to.
451      * @return Returns the same Preference object, for chaining multiple calls
452      *         into a single statement.
453      * @see #onCreateView(ViewGroup)
454      * @see #onBindView(View)
455      */
456     public View getView(View convertView, ViewGroup parent) {
457         if (convertView == null) {
458             convertView = onCreateView(parent);
459         }
460         onBindView(convertView);
461         return convertView;
462     }
463     
464     /**
465      * Creates the View to be shown for this Preference in the
466      * {@link PreferenceActivity}. The default behavior is to inflate the main
467      * layout of this Preference (see {@link #setLayoutResource(int)}. If
468      * changing this behavior, please specify a {@link ViewGroup} with ID
469      * {@link android.R.id#widget_frame}.
470      * <p>
471      * Make sure to call through to the superclass's implementation.
472      * 
473      * @param parent The parent that this View will eventually be attached to.
474      * @return The View that displays this Preference.
475      * @see #onBindView(View)
476      */
477     protected View onCreateView(ViewGroup parent) {
478         final LayoutInflater layoutInflater =
479             (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
480         
481         final View layout = layoutInflater.inflate(mLayoutResId, parent, false); 
482         
483         final ViewGroup widgetFrame = (ViewGroup) layout
484                 .findViewById(com.android.internal.R.id.widget_frame);
485         if (widgetFrame != null) {
486             if (mWidgetLayoutResId != 0) {
487                 layoutInflater.inflate(mWidgetLayoutResId, widgetFrame);
488             } else {
489                 widgetFrame.setVisibility(View.GONE);
490             }
491         }
492         return layout;
493     }
494     
495     /**
496      * Binds the created View to the data for this Preference.
497      * <p>
498      * This is a good place to grab references to custom Views in the layout and
499      * set properties on them.
500      * <p>
501      * Make sure to call through to the superclass's implementation.
502      * 
503      * @param view The View that shows this Preference.
504      * @see #onCreateView(ViewGroup)
505      */
506     protected void onBindView(View view) {
507         final TextView titleView = (TextView) view.findViewById(
508                 com.android.internal.R.id.title);
509         if (titleView != null) {
510             final CharSequence title = getTitle();
511             if (!TextUtils.isEmpty(title)) {
512                 titleView.setText(title);
513                 titleView.setVisibility(View.VISIBLE);
514             } else {
515                 titleView.setVisibility(View.GONE);
516             }
517         }
518
519         final TextView summaryView = (TextView) view.findViewById(
520                 com.android.internal.R.id.summary);
521         if (summaryView != null) {
522             final CharSequence summary = getSummary();
523             if (!TextUtils.isEmpty(summary)) {
524                 summaryView.setText(summary);
525                 summaryView.setVisibility(View.VISIBLE);
526             } else {
527                 summaryView.setVisibility(View.GONE);
528             }
529         }
530
531         ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
532         if (imageView != null) {
533             if (mIconResId != 0 || mIcon != null) {
534                 if (mIcon == null) {
535                     mIcon = getContext().getResources().getDrawable(mIconResId);
536                 }
537                 if (mIcon != null) {
538                     imageView.setImageDrawable(mIcon);
539                 }
540             }
541             imageView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
542         }
543
544         if (mShouldDisableView) {
545             setEnabledStateOnViews(view, isEnabled());
546         }
547     }
548
549     /**
550      * Makes sure the view (and any children) get the enabled state changed.
551      */
552     private void setEnabledStateOnViews(View v, boolean enabled) {
553         v.setEnabled(enabled);
554         
555         if (v instanceof ViewGroup) {
556             final ViewGroup vg = (ViewGroup) v;
557             for (int i = vg.getChildCount() - 1; i >= 0; i--) {
558                 setEnabledStateOnViews(vg.getChildAt(i), enabled);
559             }
560         }
561     }
562     
563     /**
564      * Sets the order of this Preference with respect to other
565      * Preference objects on the same level. If this is not specified, the
566      * default behavior is to sort alphabetically. The
567      * {@link PreferenceGroup#setOrderingAsAdded(boolean)} can be used to order
568      * Preference objects based on the order they appear in the XML.
569      * 
570      * @param order The order for this Preference. A lower value will be shown
571      *            first. Use {@link #DEFAULT_ORDER} to sort alphabetically or
572      *            allow ordering from XML.
573      * @see PreferenceGroup#setOrderingAsAdded(boolean)
574      * @see #DEFAULT_ORDER
575      */
576     public void setOrder(int order) {
577         if (order != mOrder) {
578             mOrder = order;
579
580             // Reorder the list 
581             notifyHierarchyChanged();
582         }
583     }
584     
585     /**
586      * Gets the order of this Preference with respect to other Preference objects
587      * on the same level.
588      * 
589      * @return The order of this Preference.
590      * @see #setOrder(int)
591      */
592     public int getOrder() {
593         return mOrder;
594     }
595
596     /**
597      * Sets the title for this Preference with a CharSequence. 
598      * This title will be placed into the ID
599      * {@link android.R.id#title} within the View created by
600      * {@link #onCreateView(ViewGroup)}.
601      * 
602      * @param title The title for this Preference.
603      */
604     public void setTitle(CharSequence title) {
605         if (title == null && mTitle != null || title != null && !title.equals(mTitle)) {
606             mTitleRes = 0;
607             mTitle = title;
608             notifyChanged();
609         }
610     }
611     
612     /**
613      * Sets the title for this Preference with a resource ID. 
614      * 
615      * @see #setTitle(CharSequence)
616      * @param titleResId The title as a resource ID.
617      */
618     public void setTitle(int titleResId) {
619         setTitle(mContext.getString(titleResId));
620         mTitleRes = titleResId;
621     }
622     
623     /**
624      * Returns the title resource ID of this Preference.  If the title did
625      * not come from a resource, 0 is returned.
626      *
627      * @return The title resource.
628      * @see #setTitle(int)
629      */
630     public int getTitleRes() {
631         return mTitleRes;
632     }
633
634     /**
635      * Returns the title of this Preference.
636      * 
637      * @return The title.
638      * @see #setTitle(CharSequence)
639      */
640     public CharSequence getTitle() {
641         return mTitle;
642     }
643
644     /**
645      * Sets the icon for this Preference with a Drawable. 
646      * This icon will be placed into the ID
647      * {@link android.R.id#icon} within the View created by
648      * {@link #onCreateView(ViewGroup)}.
649      * 
650      * @param icon The optional icon for this Preference.
651      */
652     public void setIcon(Drawable icon) {
653         if ((icon == null && mIcon != null) || (icon != null && mIcon != icon)) {
654             mIcon = icon;
655
656             notifyChanged();
657         }
658     }
659
660     /**
661      * Sets the icon for this Preference with a resource ID. 
662      * 
663      * @see #setIcon(Drawable)
664      * @param iconResId The icon as a resource ID.
665      */
666     public void setIcon(int iconResId) {
667         mIconResId = iconResId;
668         setIcon(mContext.getResources().getDrawable(iconResId));
669     }
670
671     /**
672      * Returns the icon of this Preference.
673      * 
674      * @return The icon.
675      * @see #setIcon(Drawable)
676      */
677     public Drawable getIcon() {
678         return mIcon;
679     }
680
681     /**
682      * Returns the summary of this Preference.
683      * 
684      * @return The summary.
685      * @see #setSummary(CharSequence)
686      */
687     public CharSequence getSummary() {
688         return mSummary;
689     }
690
691     /**
692      * Sets the summary for this Preference with a CharSequence. 
693      * 
694      * @param summary The summary for the preference.
695      */
696     public void setSummary(CharSequence summary) {
697         if (summary == null && mSummary != null || summary != null && !summary.equals(mSummary)) {
698             mSummary = summary;
699             notifyChanged();
700         }
701     }
702
703     /**
704      * Sets the summary for this Preference with a resource ID. 
705      * 
706      * @see #setSummary(CharSequence)
707      * @param summaryResId The summary as a resource.
708      */
709     public void setSummary(int summaryResId) {
710         setSummary(mContext.getString(summaryResId));
711     }
712     
713     /**
714      * Sets whether this Preference is enabled. If disabled, it will
715      * not handle clicks.
716      * 
717      * @param enabled Set true to enable it.
718      */
719     public void setEnabled(boolean enabled) {
720         if (mEnabled != enabled) {
721             mEnabled = enabled;
722
723             // Enabled state can change dependent preferences' states, so notify
724             notifyDependencyChange(shouldDisableDependents());
725
726             notifyChanged();
727         }
728     }
729     
730     /**
731      * Checks whether this Preference should be enabled in the list.
732      * 
733      * @return True if this Preference is enabled, false otherwise.
734      */
735     public boolean isEnabled() {
736         return mEnabled && mDependencyMet;
737     }
738
739     /**
740      * Sets whether this Preference is selectable.
741      * 
742      * @param selectable Set true to make it selectable.
743      */
744     public void setSelectable(boolean selectable) {
745         if (mSelectable != selectable) {
746             mSelectable = selectable;
747             notifyChanged();
748         }
749     }
750     
751     /**
752      * Checks whether this Preference should be selectable in the list.
753      * 
754      * @return True if it is selectable, false otherwise.
755      */
756     public boolean isSelectable() {
757         return mSelectable;
758     }
759
760     /**
761      * Sets whether this Preference should disable its view when it gets
762      * disabled.
763      * <p>
764      * For example, set this and {@link #setEnabled(boolean)} to false for
765      * preferences that are only displaying information and 1) should not be
766      * clickable 2) should not have the view set to the disabled state.
767      * 
768      * @param shouldDisableView Set true if this preference should disable its view
769      *            when the preference is disabled.
770      */
771     public void setShouldDisableView(boolean shouldDisableView) {
772         mShouldDisableView = shouldDisableView;
773         notifyChanged();
774     }
775     
776     /**
777      * Checks whether this Preference should disable its view when it's action is disabled.
778      * @see #setShouldDisableView(boolean)
779      * @return True if it should disable the view. 
780      */
781     public boolean getShouldDisableView() {
782         return mShouldDisableView;
783     }
784
785     /**
786      * Returns a unique ID for this Preference.  This ID should be unique across all
787      * Preference objects in a hierarchy.
788      * 
789      * @return A unique ID for this Preference.
790      */
791     long getId() {
792         return mId;
793     }
794     
795     /**
796      * Processes a click on the preference. This includes saving the value to
797      * the {@link SharedPreferences}. However, the overridden method should
798      * call {@link #callChangeListener(Object)} to make sure the client wants to
799      * update the preference's state with the new value.
800      */
801     protected void onClick() {
802     }
803     
804     /**
805      * Sets the key for this Preference, which is used as a key to the
806      * {@link SharedPreferences}. This should be unique for the package.
807      * 
808      * @param key The key for the preference.
809      */
810     public void setKey(String key) {
811         mKey = key;
812         
813         if (mRequiresKey && !hasKey()) {
814             requireKey();
815         }
816     }
817     
818     /**
819      * Gets the key for this Preference, which is also the key used for storing
820      * values into SharedPreferences.
821      * 
822      * @return The key.
823      */
824     public String getKey() {
825         return mKey;
826     }
827     
828     /**
829      * Checks whether the key is present, and if it isn't throws an
830      * exception. This should be called by subclasses that store preferences in
831      * the {@link SharedPreferences}.
832      * 
833      * @throws IllegalStateException If there is no key assigned.
834      */
835     void requireKey() {
836         if (mKey == null) {
837             throw new IllegalStateException("Preference does not have a key assigned.");
838         }
839         
840         mRequiresKey = true;
841     }
842     
843     /**
844      * Checks whether this Preference has a valid key.
845      * 
846      * @return True if the key exists and is not a blank string, false otherwise.
847      */
848     public boolean hasKey() {
849         return !TextUtils.isEmpty(mKey);
850     }
851     
852     /**
853      * Checks whether this Preference is persistent. If it is, it stores its value(s) into
854      * the persistent {@link SharedPreferences} storage.
855      * 
856      * @return True if it is persistent.
857      */
858     public boolean isPersistent() {
859         return mPersistent;
860     }
861     
862     /**
863      * Checks whether, at the given time this method is called,
864      * this Preference should store/restore its value(s) into the
865      * {@link SharedPreferences}. This, at minimum, checks whether this
866      * Preference is persistent and it currently has a key. Before you
867      * save/restore from the {@link SharedPreferences}, check this first.
868      * 
869      * @return True if it should persist the value.
870      */
871     protected boolean shouldPersist() {
872         return mPreferenceManager != null && isPersistent() && hasKey();
873     }
874     
875     /**
876      * Sets whether this Preference is persistent. When persistent,
877      * it stores its value(s) into the persistent {@link SharedPreferences}
878      * storage.
879      * 
880      * @param persistent Set true if it should store its value(s) into the {@link SharedPreferences}.
881      */
882     public void setPersistent(boolean persistent) {
883         mPersistent = persistent;
884     }
885     
886     /**
887      * Call this method after the user changes the preference, but before the
888      * internal state is set. This allows the client to ignore the user value.
889      * 
890      * @param newValue The new value of this Preference.
891      * @return True if the user value should be set as the preference
892      *         value (and persisted).
893      */
894     protected boolean callChangeListener(Object newValue) {
895         return mOnChangeListener == null ? true : mOnChangeListener.onPreferenceChange(this, newValue);
896     }
897     
898     /**
899      * Sets the callback to be invoked when this Preference is changed by the
900      * user (but before the internal state has been updated).
901      * 
902      * @param onPreferenceChangeListener The callback to be invoked.
903      */
904     public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) {
905         mOnChangeListener = onPreferenceChangeListener;
906     }
907
908     /**
909      * Returns the callback to be invoked when this Preference is changed by the
910      * user (but before the internal state has been updated).
911      * 
912      * @return The callback to be invoked.
913      */
914     public OnPreferenceChangeListener getOnPreferenceChangeListener() {
915         return mOnChangeListener;
916     }
917
918     /**
919      * Sets the callback to be invoked when this Preference is clicked.
920      * 
921      * @param onPreferenceClickListener The callback to be invoked.
922      */
923     public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
924         mOnClickListener = onPreferenceClickListener;
925     }
926
927     /**
928      * Returns the callback to be invoked when this Preference is clicked.
929      * 
930      * @return The callback to be invoked.
931      */
932     public OnPreferenceClickListener getOnPreferenceClickListener() {
933         return mOnClickListener;
934     }
935
936     /**
937      * Called when a click should be performed.
938      * 
939      * @param preferenceScreen A {@link PreferenceScreen} whose hierarchy click
940      *            listener should be called in the proper order (between other
941      *            processing). May be null.
942      */
943     void performClick(PreferenceScreen preferenceScreen) {
944         
945         if (!isEnabled()) {
946             return;
947         }
948         
949         onClick();
950         
951         if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) {
952             return;
953         }
954         
955         PreferenceManager preferenceManager = getPreferenceManager();
956         if (preferenceManager != null) {
957             PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
958                     .getOnPreferenceTreeClickListener();
959             if (preferenceScreen != null && listener != null
960                     && listener.onPreferenceTreeClick(preferenceScreen, this)) {
961                 return;
962             }
963         }
964         
965         if (mIntent != null) {
966             Context context = getContext();
967             context.startActivity(mIntent);
968         }
969     }
970
971     /**
972      * Allows a Preference to intercept key events without having focus.
973      * For example, SeekBarPreference uses this to intercept +/- to adjust
974      * the progress.
975      * @return True if the Preference handled the key. Returns false by default.
976      * @hide
977      */
978     public boolean onKey(View v, int keyCode, KeyEvent event) {
979         return false;
980     }
981     
982     /**
983      * Returns the {@link android.content.Context} of this Preference. 
984      * Each Preference in a Preference hierarchy can be
985      * from different Context (for example, if multiple activities provide preferences into a single
986      * {@link PreferenceActivity}). This Context will be used to save the Preference values.
987      * 
988      * @return The Context of this Preference.
989      */
990     public Context getContext() {
991         return mContext;
992     }
993     
994     /**
995      * Returns the {@link SharedPreferences} where this Preference can read its
996      * value(s). Usually, it's easier to use one of the helper read methods:
997      * {@link #getPersistedBoolean(boolean)}, {@link #getPersistedFloat(float)},
998      * {@link #getPersistedInt(int)}, {@link #getPersistedLong(long)},
999      * {@link #getPersistedString(String)}. To save values, see
1000      * {@link #getEditor()}.
1001      * <p>
1002      * In some cases, writes to the {@link #getEditor()} will not be committed
1003      * right away and hence not show up in the returned
1004      * {@link SharedPreferences}, this is intended behavior to improve
1005      * performance.
1006      * 
1007      * @return The {@link SharedPreferences} where this Preference reads its
1008      *         value(s), or null if it isn't attached to a Preference hierarchy.
1009      * @see #getEditor()
1010      */
1011     public SharedPreferences getSharedPreferences() {
1012         if (mPreferenceManager == null) {
1013             return null;
1014         }
1015         
1016         return mPreferenceManager.getSharedPreferences();
1017     }
1018     
1019     /**
1020      * Returns an {@link SharedPreferences.Editor} where this Preference can
1021      * save its value(s). Usually it's easier to use one of the helper save
1022      * methods: {@link #persistBoolean(boolean)}, {@link #persistFloat(float)},
1023      * {@link #persistInt(int)}, {@link #persistLong(long)},
1024      * {@link #persistString(String)}. To read values, see
1025      * {@link #getSharedPreferences()}. If {@link #shouldCommit()} returns
1026      * true, it is this Preference's responsibility to commit.
1027      * <p>
1028      * In some cases, writes to this will not be committed right away and hence
1029      * not show up in the SharedPreferences, this is intended behavior to
1030      * improve performance.
1031      * 
1032      * @return A {@link SharedPreferences.Editor} where this preference saves
1033      *         its value(s), or null if it isn't attached to a Preference
1034      *         hierarchy.
1035      * @see #shouldCommit()
1036      * @see #getSharedPreferences()
1037      */
1038     public SharedPreferences.Editor getEditor() {
1039         if (mPreferenceManager == null) {
1040             return null;
1041         }
1042         
1043         return mPreferenceManager.getEditor();
1044     }
1045     
1046     /**
1047      * Returns whether the {@link Preference} should commit its saved value(s) in
1048      * {@link #getEditor()}. This may return false in situations where batch
1049      * committing is being done (by the manager) to improve performance.
1050      * 
1051      * @return Whether the Preference should commit its saved value(s).
1052      * @see #getEditor()
1053      */
1054     public boolean shouldCommit() {
1055         if (mPreferenceManager == null) {
1056             return false;
1057         }
1058         
1059         return mPreferenceManager.shouldCommit();
1060     }
1061     
1062     /**
1063      * Compares Preference objects based on order (if set), otherwise alphabetically on the titles.
1064      * 
1065      * @param another The Preference to compare to this one.
1066      * @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another</var>;
1067      *          greater than 0 if this Preference sorts after <var>another</var>.
1068      */
1069     public int compareTo(Preference another) {
1070         if (mOrder != DEFAULT_ORDER
1071                 || (mOrder == DEFAULT_ORDER && another.mOrder != DEFAULT_ORDER)) {
1072             // Do order comparison
1073             return mOrder - another.mOrder; 
1074         } else if (mTitle == null) {
1075             return 1;
1076         } else if (another.mTitle == null) {
1077             return -1;
1078         } else {
1079             // Do name comparison
1080             return CharSequences.compareToIgnoreCase(mTitle, another.mTitle);
1081         }
1082     }
1083     
1084     /**
1085      * Sets the internal change listener.
1086      * 
1087      * @param listener The listener.
1088      * @see #notifyChanged()
1089      */
1090     final void setOnPreferenceChangeInternalListener(OnPreferenceChangeInternalListener listener) {
1091         mListener = listener;
1092     }
1093
1094     /**
1095      * Should be called when the data of this {@link Preference} has changed.
1096      */
1097     protected void notifyChanged() {
1098         if (mListener != null) {
1099             mListener.onPreferenceChange(this);
1100         }
1101     }
1102     
1103     /**
1104      * Should be called when a Preference has been
1105      * added/removed from this group, or the ordering should be
1106      * re-evaluated.
1107      */
1108     protected void notifyHierarchyChanged() {
1109         if (mListener != null) {
1110             mListener.onPreferenceHierarchyChange(this);
1111         }
1112     }
1113
1114     /**
1115      * Gets the {@link PreferenceManager} that manages this Preference object's tree.
1116      * 
1117      * @return The {@link PreferenceManager}.
1118      */
1119     public PreferenceManager getPreferenceManager() {
1120         return mPreferenceManager;
1121     }
1122     
1123     /**
1124      * Called when this Preference has been attached to a Preference hierarchy.
1125      * Make sure to call the super implementation.
1126      * 
1127      * @param preferenceManager The PreferenceManager of the hierarchy.
1128      */
1129     protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
1130         mPreferenceManager = preferenceManager;
1131         
1132         mId = preferenceManager.getNextId();
1133         
1134         dispatchSetInitialValue();
1135     }
1136     
1137     /**
1138      * Called when the Preference hierarchy has been attached to the
1139      * {@link PreferenceActivity}. This can also be called when this
1140      * Preference has been attached to a group that was already attached
1141      * to the {@link PreferenceActivity}.
1142      */
1143     protected void onAttachedToActivity() {
1144         // At this point, the hierarchy that this preference is in is connected
1145         // with all other preferences.
1146         registerDependency();
1147     }
1148
1149     private void registerDependency() {
1150         
1151         if (TextUtils.isEmpty(mDependencyKey)) return;
1152         
1153         Preference preference = findPreferenceInHierarchy(mDependencyKey);
1154         if (preference != null) {
1155             preference.registerDependent(this);
1156         } else {
1157             throw new IllegalStateException("Dependency \"" + mDependencyKey
1158                     + "\" not found for preference \"" + mKey + "\" (title: \"" + mTitle + "\"");
1159         }
1160     }
1161
1162     private void unregisterDependency() {
1163         if (mDependencyKey != null) {
1164             final Preference oldDependency = findPreferenceInHierarchy(mDependencyKey);
1165             if (oldDependency != null) {
1166                 oldDependency.unregisterDependent(this);
1167             }
1168         }
1169     }
1170     
1171     /**
1172      * Finds a Preference in this hierarchy (the whole thing,
1173      * even above/below your {@link PreferenceScreen} screen break) with the given
1174      * key.
1175      * <p>
1176      * This only functions after we have been attached to a hierarchy.
1177      * 
1178      * @param key The key of the Preference to find.
1179      * @return The Preference that uses the given key.
1180      */
1181     protected Preference findPreferenceInHierarchy(String key) {
1182         if (TextUtils.isEmpty(key) || mPreferenceManager == null) {
1183             return null;
1184         }
1185         
1186         return mPreferenceManager.findPreference(key);
1187     }
1188     
1189     /**
1190      * Adds a dependent Preference on this Preference so we can notify it.
1191      * Usually, the dependent Preference registers itself (it's good for it to
1192      * know it depends on something), so please use
1193      * {@link Preference#setDependency(String)} on the dependent Preference.
1194      * 
1195      * @param dependent The dependent Preference that will be enabled/disabled
1196      *            according to the state of this Preference.
1197      */
1198     private void registerDependent(Preference dependent) {
1199         if (mDependents == null) {
1200             mDependents = new ArrayList<Preference>();
1201         }
1202         
1203         mDependents.add(dependent);
1204         
1205         dependent.onDependencyChanged(this, shouldDisableDependents());
1206     }
1207     
1208     /**
1209      * Removes a dependent Preference on this Preference.
1210      * 
1211      * @param dependent The dependent Preference that will be enabled/disabled
1212      *            according to the state of this Preference.
1213      * @return Returns the same Preference object, for chaining multiple calls
1214      *         into a single statement.
1215      */
1216     private void unregisterDependent(Preference dependent) {
1217         if (mDependents != null) {
1218             mDependents.remove(dependent);
1219         }
1220     }
1221     
1222     /**
1223      * Notifies any listening dependents of a change that affects the
1224      * dependency.
1225      * 
1226      * @param disableDependents Whether this Preference should disable
1227      *            its dependents.
1228      */
1229     public void notifyDependencyChange(boolean disableDependents) {
1230         final List<Preference> dependents = mDependents;
1231         
1232         if (dependents == null) {
1233             return;
1234         }
1235         
1236         final int dependentsCount = dependents.size();
1237         for (int i = 0; i < dependentsCount; i++) {
1238             dependents.get(i).onDependencyChanged(this, disableDependents);
1239         }
1240     }
1241
1242     /**
1243      * Called when the dependency changes.
1244      * 
1245      * @param dependency The Preference that this Preference depends on.
1246      * @param disableDependent Set true to disable this Preference.
1247      */
1248     public void onDependencyChanged(Preference dependency, boolean disableDependent) {
1249         if (mDependencyMet == disableDependent) {
1250             mDependencyMet = !disableDependent;
1251
1252             // Enabled state can change dependent preferences' states, so notify
1253             notifyDependencyChange(shouldDisableDependents());
1254
1255             notifyChanged();
1256         }
1257     }
1258     
1259     /**
1260      * Checks whether this preference's dependents should currently be
1261      * disabled.
1262      * 
1263      * @return True if the dependents should be disabled, otherwise false.
1264      */
1265     public boolean shouldDisableDependents() {
1266         return !isEnabled();
1267     }
1268     
1269     /**
1270      * Sets the key of a Preference that this Preference will depend on. If that
1271      * Preference is not set or is off, this Preference will be disabled.
1272      * 
1273      * @param dependencyKey The key of the Preference that this depends on.
1274      */
1275     public void setDependency(String dependencyKey) {
1276         // Unregister the old dependency, if we had one
1277         unregisterDependency();
1278         
1279         // Register the new
1280         mDependencyKey = dependencyKey;
1281         registerDependency();
1282     }
1283     
1284     /**
1285      * Returns the key of the dependency on this Preference.
1286      * 
1287      * @return The key of the dependency.
1288      * @see #setDependency(String)
1289      */
1290     public String getDependency() {
1291         return mDependencyKey;
1292     }
1293     
1294     /**
1295      * Called when this Preference is being removed from the hierarchy. You
1296      * should remove any references to this Preference that you know about. Make
1297      * sure to call through to the superclass implementation.
1298      */
1299     protected void onPrepareForRemoval() {
1300         unregisterDependency();
1301     }
1302     
1303     /**
1304      * Sets the default value for this Preference, which will be set either if
1305      * persistence is off or persistence is on and the preference is not found
1306      * in the persistent storage.
1307      * 
1308      * @param defaultValue The default value.
1309      */
1310     public void setDefaultValue(Object defaultValue) {
1311         mDefaultValue = defaultValue;
1312     }
1313     
1314     private void dispatchSetInitialValue() {
1315         // By now, we know if we are persistent.
1316         final boolean shouldPersist = shouldPersist();
1317         if (!shouldPersist || !getSharedPreferences().contains(mKey)) {
1318             if (mDefaultValue != null) {
1319                 onSetInitialValue(false, mDefaultValue);
1320             }
1321         } else {
1322             onSetInitialValue(true, null);
1323         }
1324     }
1325     
1326     /**
1327      * Implement this to set the initial value of the Preference. 
1328      * <p>
1329      * If <var>restorePersistedValue</var> is true, you should restore the 
1330      * Preference value from the {@link android.content.SharedPreferences}. If 
1331      * <var>restorePersistedValue</var> is false, you should set the Preference 
1332      * value to defaultValue that is given (and possibly store to SharedPreferences 
1333      * if {@link #shouldPersist()} is true).
1334      * <p>
1335      * This may not always be called. One example is if it should not persist
1336      * but there is no default value given.
1337      * 
1338      * @param restorePersistedValue True to restore the persisted value;
1339      *            false to use the given <var>defaultValue</var>.
1340      * @param defaultValue The default value for this Preference. Only use this
1341      *            if <var>restorePersistedValue</var> is false.
1342      */
1343     protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
1344     }
1345
1346     private void tryCommit(SharedPreferences.Editor editor) {
1347         if (mPreferenceManager.shouldCommit()) {
1348             try {
1349                 editor.apply();
1350             } catch (AbstractMethodError unused) {
1351                 // The app injected its own pre-Gingerbread
1352                 // SharedPreferences.Editor implementation without
1353                 // an apply method.
1354                 editor.commit();
1355             }
1356         }
1357     }
1358     
1359     /**
1360      * Attempts to persist a String to the {@link android.content.SharedPreferences}.
1361      * <p>
1362      * This will check if this Preference is persistent, get an editor from
1363      * the {@link PreferenceManager}, put in the string, and check if we should commit (and
1364      * commit if so).
1365      * 
1366      * @param value The value to persist.
1367      * @return True if the Preference is persistent. (This is not whether the
1368      *         value was persisted, since we may not necessarily commit if there
1369      *         will be a batch commit later.)
1370      * @see #getPersistedString(String)
1371      */
1372     protected boolean persistString(String value) {
1373         if (shouldPersist()) {
1374             // Shouldn't store null
1375             if (value == getPersistedString(null)) {
1376                 // It's already there, so the same as persisting
1377                 return true;
1378             }
1379             
1380             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1381             editor.putString(mKey, value);
1382             tryCommit(editor);
1383             return true;
1384         }
1385         return false;
1386     }
1387     
1388     /**
1389      * Attempts to get a persisted String from the {@link android.content.SharedPreferences}.
1390      * <p>
1391      * This will check if this Preference is persistent, get the SharedPreferences
1392      * from the {@link PreferenceManager}, and get the value.
1393      * 
1394      * @param defaultReturnValue The default value to return if either the
1395      *            Preference is not persistent or the Preference is not in the
1396      *            shared preferences.
1397      * @return The value from the SharedPreferences or the default return
1398      *         value.
1399      * @see #persistString(String)
1400      */
1401     protected String getPersistedString(String defaultReturnValue) {
1402         if (!shouldPersist()) {
1403             return defaultReturnValue;
1404         }
1405         
1406         return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue);
1407     }
1408     
1409     /**
1410      * Attempts to persist a set of Strings to the {@link android.content.SharedPreferences}.
1411      * <p>
1412      * This will check if this Preference is persistent, get an editor from
1413      * the {@link PreferenceManager}, put in the strings, and check if we should commit (and
1414      * commit if so).
1415      * 
1416      * @param values The values to persist.
1417      * @return True if the Preference is persistent. (This is not whether the
1418      *         value was persisted, since we may not necessarily commit if there
1419      *         will be a batch commit later.)
1420      * @see #getPersistedString(Set)
1421      * 
1422      * @hide Pending API approval
1423      */
1424     protected boolean persistStringSet(Set<String> values) {
1425         if (shouldPersist()) {
1426             // Shouldn't store null
1427             if (values.equals(getPersistedStringSet(null))) {
1428                 // It's already there, so the same as persisting
1429                 return true;
1430             }
1431             
1432             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1433             editor.putStringSet(mKey, values);
1434             tryCommit(editor);
1435             return true;
1436         }
1437         return false;
1438     }
1439
1440     /**
1441      * Attempts to get a persisted set of Strings from the
1442      * {@link android.content.SharedPreferences}.
1443      * <p>
1444      * This will check if this Preference is persistent, get the SharedPreferences
1445      * from the {@link PreferenceManager}, and get the value.
1446      * 
1447      * @param defaultReturnValue The default value to return if either the
1448      *            Preference is not persistent or the Preference is not in the
1449      *            shared preferences.
1450      * @return The value from the SharedPreferences or the default return
1451      *         value.
1452      * @see #persistStringSet(Set)
1453      * 
1454      * @hide Pending API approval
1455      */
1456     protected Set<String> getPersistedStringSet(Set<String> defaultReturnValue) {
1457         if (!shouldPersist()) {
1458             return defaultReturnValue;
1459         }
1460         
1461         return mPreferenceManager.getSharedPreferences().getStringSet(mKey, defaultReturnValue);
1462     }
1463     
1464     /**
1465      * Attempts to persist an int to the {@link android.content.SharedPreferences}.
1466      * 
1467      * @param value The value to persist.
1468      * @return True if the Preference is persistent. (This is not whether the
1469      *         value was persisted, since we may not necessarily commit if there
1470      *         will be a batch commit later.)
1471      * @see #persistString(String)
1472      * @see #getPersistedInt(int)
1473      */
1474     protected boolean persistInt(int value) {
1475         if (shouldPersist()) {
1476             if (value == getPersistedInt(~value)) {
1477                 // It's already there, so the same as persisting
1478                 return true;
1479             }
1480             
1481             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1482             editor.putInt(mKey, value);
1483             tryCommit(editor);
1484             return true;
1485         }
1486         return false;
1487     }
1488     
1489     /**
1490      * Attempts to get a persisted int from the {@link android.content.SharedPreferences}.
1491      * 
1492      * @param defaultReturnValue The default value to return if either this
1493      *            Preference is not persistent or this Preference is not in the
1494      *            SharedPreferences.
1495      * @return The value from the SharedPreferences or the default return
1496      *         value.
1497      * @see #getPersistedString(String)
1498      * @see #persistInt(int)
1499      */
1500     protected int getPersistedInt(int defaultReturnValue) {
1501         if (!shouldPersist()) {
1502             return defaultReturnValue;
1503         }
1504         
1505         return mPreferenceManager.getSharedPreferences().getInt(mKey, defaultReturnValue);
1506     }
1507     
1508     /**
1509      * Attempts to persist a float to the {@link android.content.SharedPreferences}.
1510      * 
1511      * @param value The value to persist.
1512      * @return True if this Preference is persistent. (This is not whether the
1513      *         value was persisted, since we may not necessarily commit if there
1514      *         will be a batch commit later.)
1515      * @see #persistString(String)
1516      * @see #getPersistedFloat(float)
1517      */
1518     protected boolean persistFloat(float value) {
1519         if (shouldPersist()) {
1520             if (value == getPersistedFloat(Float.NaN)) {
1521                 // It's already there, so the same as persisting
1522                 return true;
1523             }
1524
1525             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1526             editor.putFloat(mKey, value);
1527             tryCommit(editor);
1528             return true;
1529         }
1530         return false;
1531     }
1532     
1533     /**
1534      * Attempts to get a persisted float from the {@link android.content.SharedPreferences}.
1535      * 
1536      * @param defaultReturnValue The default value to return if either this
1537      *            Preference is not persistent or this Preference is not in the
1538      *            SharedPreferences.
1539      * @return The value from the SharedPreferences or the default return
1540      *         value.
1541      * @see #getPersistedString(String)
1542      * @see #persistFloat(float)
1543      */
1544     protected float getPersistedFloat(float defaultReturnValue) {
1545         if (!shouldPersist()) {
1546             return defaultReturnValue;
1547         }
1548         
1549         return mPreferenceManager.getSharedPreferences().getFloat(mKey, defaultReturnValue);
1550     }
1551     
1552     /**
1553      * Attempts to persist a long to the {@link android.content.SharedPreferences}.
1554      * 
1555      * @param value The value to persist.
1556      * @return True if this Preference is persistent. (This is not whether the
1557      *         value was persisted, since we may not necessarily commit if there
1558      *         will be a batch commit later.)
1559      * @see #persistString(String)
1560      * @see #getPersistedLong(long)
1561      */
1562     protected boolean persistLong(long value) {
1563         if (shouldPersist()) {
1564             if (value == getPersistedLong(~value)) {
1565                 // It's already there, so the same as persisting
1566                 return true;
1567             }
1568             
1569             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1570             editor.putLong(mKey, value);
1571             tryCommit(editor);
1572             return true;
1573         }
1574         return false;
1575     }
1576     
1577     /**
1578      * Attempts to get a persisted long from the {@link android.content.SharedPreferences}.
1579      * 
1580      * @param defaultReturnValue The default value to return if either this
1581      *            Preference is not persistent or this Preference is not in the
1582      *            SharedPreferences.
1583      * @return The value from the SharedPreferences or the default return
1584      *         value.
1585      * @see #getPersistedString(String)
1586      * @see #persistLong(long)
1587      */
1588     protected long getPersistedLong(long defaultReturnValue) {
1589         if (!shouldPersist()) {
1590             return defaultReturnValue;
1591         }
1592         
1593         return mPreferenceManager.getSharedPreferences().getLong(mKey, defaultReturnValue);
1594     }
1595     
1596     /**
1597      * Attempts to persist a boolean to the {@link android.content.SharedPreferences}.
1598      * 
1599      * @param value The value to persist.
1600      * @return True if this Preference is persistent. (This is not whether the
1601      *         value was persisted, since we may not necessarily commit if there
1602      *         will be a batch commit later.)
1603      * @see #persistString(String)
1604      * @see #getPersistedBoolean(boolean)
1605      */
1606     protected boolean persistBoolean(boolean value) {
1607         if (shouldPersist()) {
1608             if (value == getPersistedBoolean(!value)) {
1609                 // It's already there, so the same as persisting
1610                 return true;
1611             }
1612             
1613             SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1614             editor.putBoolean(mKey, value);
1615             tryCommit(editor);
1616             return true;
1617         }
1618         return false;
1619     }
1620     
1621     /**
1622      * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}.
1623      * 
1624      * @param defaultReturnValue The default value to return if either this
1625      *            Preference is not persistent or this Preference is not in the
1626      *            SharedPreferences.
1627      * @return The value from the SharedPreferences or the default return
1628      *         value.
1629      * @see #getPersistedString(String)
1630      * @see #persistBoolean(boolean)
1631      */
1632     protected boolean getPersistedBoolean(boolean defaultReturnValue) {
1633         if (!shouldPersist()) {
1634             return defaultReturnValue;
1635         }
1636         
1637         return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue);
1638     }
1639     
1640     boolean hasSpecifiedLayout() {
1641         return mHasSpecifiedLayout;
1642     }
1643     
1644     @Override
1645     public String toString() {
1646         return getFilterableStringBuilder().toString();
1647     }
1648         
1649     /**
1650      * Returns the text that will be used to filter this Preference depending on
1651      * user input.
1652      * <p>
1653      * If overridding and calling through to the superclass, make sure to prepend
1654      * your additions with a space.
1655      * 
1656      * @return Text as a {@link StringBuilder} that will be used to filter this
1657      *         preference. By default, this is the title and summary
1658      *         (concatenated with a space).
1659      */
1660     StringBuilder getFilterableStringBuilder() {
1661         StringBuilder sb = new StringBuilder();
1662         CharSequence title = getTitle();
1663         if (!TextUtils.isEmpty(title)) {
1664             sb.append(title).append(' ');
1665         }
1666         CharSequence summary = getSummary();
1667         if (!TextUtils.isEmpty(summary)) {
1668             sb.append(summary).append(' ');
1669         }
1670         if (sb.length() > 0) {
1671             // Drop the last space
1672             sb.setLength(sb.length() - 1);
1673         }
1674         return sb;
1675     }
1676
1677     /**
1678      * Store this Preference hierarchy's frozen state into the given container.
1679      * 
1680      * @param container The Bundle in which to save the instance of this Preference.
1681      * 
1682      * @see #restoreHierarchyState
1683      * @see #onSaveInstanceState
1684      */
1685     public void saveHierarchyState(Bundle container) {
1686         dispatchSaveInstanceState(container);
1687     }
1688
1689     /**
1690      * Called by {@link #saveHierarchyState} to store the instance for this Preference and its children.
1691      * May be overridden to modify how the save happens for children. For example, some
1692      * Preference objects may want to not store an instance for their children.
1693      * 
1694      * @param container The Bundle in which to save the instance of this Preference.
1695      * 
1696      * @see #saveHierarchyState
1697      * @see #onSaveInstanceState
1698      */
1699     void dispatchSaveInstanceState(Bundle container) {
1700         if (hasKey()) {
1701             mBaseMethodCalled = false;
1702             Parcelable state = onSaveInstanceState();
1703             if (!mBaseMethodCalled) {
1704                 throw new IllegalStateException(
1705                         "Derived class did not call super.onSaveInstanceState()");
1706             }
1707             if (state != null) {
1708                 container.putParcelable(mKey, state);
1709             }
1710         }
1711     }
1712
1713     /**
1714      * Hook allowing a Preference to generate a representation of its internal
1715      * state that can later be used to create a new instance with that same
1716      * state. This state should only contain information that is not persistent
1717      * or can be reconstructed later.
1718      * 
1719      * @return A Parcelable object containing the current dynamic state of
1720      *         this Preference, or null if there is nothing interesting to save.
1721      *         The default implementation returns null.
1722      * @see #onRestoreInstanceState
1723      * @see #saveHierarchyState
1724      */
1725     protected Parcelable onSaveInstanceState() {
1726         mBaseMethodCalled = true;
1727         return BaseSavedState.EMPTY_STATE;
1728     }
1729
1730     /**
1731      * Restore this Preference hierarchy's previously saved state from the given container.
1732      * 
1733      * @param container The Bundle that holds the previously saved state.
1734      * 
1735      * @see #saveHierarchyState
1736      * @see #onRestoreInstanceState
1737      */
1738     public void restoreHierarchyState(Bundle container) {
1739         dispatchRestoreInstanceState(container);
1740     }
1741
1742     /**
1743      * Called by {@link #restoreHierarchyState} to retrieve the saved state for this
1744      * Preference and its children. May be overridden to modify how restoring
1745      * happens to the children of a Preference. For example, some Preference objects may
1746      * not want to save state for their children.
1747      * 
1748      * @param container The Bundle that holds the previously saved state.
1749      * @see #restoreHierarchyState
1750      * @see #onRestoreInstanceState
1751      */
1752     void dispatchRestoreInstanceState(Bundle container) {
1753         if (hasKey()) {
1754             Parcelable state = container.getParcelable(mKey);
1755             if (state != null) {
1756                 mBaseMethodCalled = false;
1757                 onRestoreInstanceState(state);
1758                 if (!mBaseMethodCalled) {
1759                     throw new IllegalStateException(
1760                             "Derived class did not call super.onRestoreInstanceState()");
1761                 }
1762             }
1763         }
1764     }
1765
1766     /**
1767      * Hook allowing a Preference to re-apply a representation of its internal
1768      * state that had previously been generated by {@link #onSaveInstanceState}.
1769      * This function will never be called with a null state.
1770      * 
1771      * @param state The saved state that had previously been returned by
1772      *            {@link #onSaveInstanceState}.
1773      * @see #onSaveInstanceState
1774      * @see #restoreHierarchyState
1775      */
1776     protected void onRestoreInstanceState(Parcelable state) {
1777         mBaseMethodCalled = true;
1778         if (state != BaseSavedState.EMPTY_STATE && state != null) {
1779             throw new IllegalArgumentException("Wrong state class -- expecting Preference State");
1780         }
1781     }
1782
1783     /**
1784      * A base class for managing the instance state of a {@link Preference}.
1785      */
1786     public static class BaseSavedState extends AbsSavedState {
1787         public BaseSavedState(Parcel source) {
1788             super(source);
1789         }
1790
1791         public BaseSavedState(Parcelable superState) {
1792             super(superState);
1793         }
1794         
1795         public static final Parcelable.Creator<BaseSavedState> CREATOR =
1796                 new Parcelable.Creator<BaseSavedState>() {
1797             public BaseSavedState createFromParcel(Parcel in) {
1798                 return new BaseSavedState(in);
1799             }
1800
1801             public BaseSavedState[] newArray(int size) {
1802                 return new BaseSavedState[size];
1803             }
1804         };
1805     }
1806
1807 }