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