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