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