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