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