blob: 8df4339f3740bbb60a1ce0861d6c41568ed18d06 [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) {
Jeff Sharkey0f1c3af2012-04-03 20:46:42 -0700500 final TextView titleView = (TextView) view.findViewById(
501 com.android.internal.R.id.title);
502 if (titleView != null) {
503 final CharSequence title = getTitle();
504 if (!TextUtils.isEmpty(title)) {
505 titleView.setText(title);
506 titleView.setVisibility(View.VISIBLE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 } else {
Jeff Sharkey0f1c3af2012-04-03 20:46:42 -0700508 titleView.setVisibility(View.GONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 }
510 }
Jeff Sharkey0f1c3af2012-04-03 20:46:42 -0700511
512 final TextView summaryView = (TextView) view.findViewById(
513 com.android.internal.R.id.summary);
514 if (summaryView != null) {
515 final CharSequence summary = getSummary();
516 if (!TextUtils.isEmpty(summary)) {
517 summaryView.setText(summary);
518 summaryView.setVisibility(View.VISIBLE);
519 } else {
520 summaryView.setVisibility(View.GONE);
521 }
522 }
523
Amith Yamasanib65897b2010-11-17 13:49:27 -0800524 ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
Amith Yamasani405c1af2011-05-26 13:08:25 -0700525 if (imageView != null) {
526 if (mIconResId != 0 || mIcon != null) {
527 if (mIcon == null) {
528 mIcon = getContext().getResources().getDrawable(mIconResId);
529 }
530 if (mIcon != null) {
531 imageView.setImageDrawable(mIcon);
532 }
Amith Yamasanib65897b2010-11-17 13:49:27 -0800533 }
Amith Yamasani405c1af2011-05-26 13:08:25 -0700534 imageView.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
Amith Yamasanib65897b2010-11-17 13:49:27 -0800535 }
Amith Yamasani405c1af2011-05-26 13:08:25 -0700536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 if (mShouldDisableView) {
538 setEnabledStateOnViews(view, isEnabled());
539 }
540 }
Amith Yamasanib65897b2010-11-17 13:49:27 -0800541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 /**
543 * Makes sure the view (and any children) get the enabled state changed.
544 */
545 private void setEnabledStateOnViews(View v, boolean enabled) {
546 v.setEnabled(enabled);
547
548 if (v instanceof ViewGroup) {
549 final ViewGroup vg = (ViewGroup) v;
550 for (int i = vg.getChildCount() - 1; i >= 0; i--) {
551 setEnabledStateOnViews(vg.getChildAt(i), enabled);
552 }
553 }
554 }
555
556 /**
557 * Sets the order of this Preference with respect to other
558 * Preference objects on the same level. If this is not specified, the
559 * default behavior is to sort alphabetically. The
560 * {@link PreferenceGroup#setOrderingAsAdded(boolean)} can be used to order
561 * Preference objects based on the order they appear in the XML.
562 *
563 * @param order The order for this Preference. A lower value will be shown
564 * first. Use {@link #DEFAULT_ORDER} to sort alphabetically or
565 * allow ordering from XML.
566 * @see PreferenceGroup#setOrderingAsAdded(boolean)
567 * @see #DEFAULT_ORDER
568 */
569 public void setOrder(int order) {
570 if (order != mOrder) {
571 mOrder = order;
572
573 // Reorder the list
574 notifyHierarchyChanged();
575 }
576 }
577
578 /**
579 * Gets the order of this Preference with respect to other Preference objects
580 * on the same level.
581 *
582 * @return The order of this Preference.
583 * @see #setOrder(int)
584 */
585 public int getOrder() {
586 return mOrder;
587 }
588
589 /**
590 * Sets the title for this Preference with a CharSequence.
591 * This title will be placed into the ID
592 * {@link android.R.id#title} within the View created by
593 * {@link #onCreateView(ViewGroup)}.
594 *
595 * @param title The title for this Preference.
596 */
597 public void setTitle(CharSequence title) {
598 if (title == null && mTitle != null || title != null && !title.equals(mTitle)) {
Dianne Hackborne72f2372011-03-16 10:43:18 -0700599 mTitleRes = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 mTitle = title;
601 notifyChanged();
602 }
603 }
604
605 /**
606 * Sets the title for this Preference with a resource ID.
607 *
608 * @see #setTitle(CharSequence)
609 * @param titleResId The title as a resource ID.
610 */
611 public void setTitle(int titleResId) {
612 setTitle(mContext.getString(titleResId));
Dianne Hackborne72f2372011-03-16 10:43:18 -0700613 mTitleRes = titleResId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 }
615
616 /**
Dianne Hackborne72f2372011-03-16 10:43:18 -0700617 * Returns the title resource ID of this Preference. If the title did
618 * not come from a resource, 0 is returned.
619 *
620 * @return The title resource.
621 * @see #setTitle(int)
622 */
623 public int getTitleRes() {
624 return mTitleRes;
625 }
626
627 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 * Returns the title of this Preference.
629 *
630 * @return The title.
631 * @see #setTitle(CharSequence)
632 */
633 public CharSequence getTitle() {
634 return mTitle;
635 }
636
637 /**
Amith Yamasanib65897b2010-11-17 13:49:27 -0800638 * Sets the icon for this Preference with a Drawable.
639 * This icon will be placed into the ID
640 * {@link android.R.id#icon} within the View created by
641 * {@link #onCreateView(ViewGroup)}.
642 *
643 * @param icon The optional icon for this Preference.
644 */
645 public void setIcon(Drawable icon) {
646 if ((icon == null && mIcon != null) || (icon != null && mIcon != icon)) {
647 mIcon = icon;
Amith Yamasani405c1af2011-05-26 13:08:25 -0700648
Amith Yamasanib65897b2010-11-17 13:49:27 -0800649 notifyChanged();
650 }
651 }
652
653 /**
654 * Sets the icon for this Preference with a resource ID.
655 *
656 * @see #setIcon(Drawable)
657 * @param iconResId The icon as a resource ID.
658 */
659 public void setIcon(int iconResId) {
660 mIconResId = iconResId;
661 setIcon(mContext.getResources().getDrawable(iconResId));
662 }
663
664 /**
665 * Returns the icon of this Preference.
666 *
667 * @return The icon.
668 * @see #setIcon(Drawable)
669 */
670 public Drawable getIcon() {
671 return mIcon;
672 }
673
674 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 * Returns the summary of this Preference.
676 *
677 * @return The summary.
678 * @see #setSummary(CharSequence)
679 */
680 public CharSequence getSummary() {
681 return mSummary;
682 }
683
684 /**
685 * Sets the summary for this Preference with a CharSequence.
686 *
687 * @param summary The summary for the preference.
688 */
689 public void setSummary(CharSequence summary) {
690 if (summary == null && mSummary != null || summary != null && !summary.equals(mSummary)) {
691 mSummary = summary;
692 notifyChanged();
693 }
694 }
695
696 /**
697 * Sets the summary for this Preference with a resource ID.
698 *
699 * @see #setSummary(CharSequence)
700 * @param summaryResId The summary as a resource.
701 */
702 public void setSummary(int summaryResId) {
703 setSummary(mContext.getString(summaryResId));
704 }
705
706 /**
707 * Sets whether this Preference is enabled. If disabled, it will
708 * not handle clicks.
709 *
710 * @param enabled Set true to enable it.
711 */
712 public void setEnabled(boolean enabled) {
713 if (mEnabled != enabled) {
714 mEnabled = enabled;
715
716 // Enabled state can change dependent preferences' states, so notify
717 notifyDependencyChange(shouldDisableDependents());
718
719 notifyChanged();
720 }
721 }
722
723 /**
724 * Checks whether this Preference should be enabled in the list.
725 *
726 * @return True if this Preference is enabled, false otherwise.
727 */
728 public boolean isEnabled() {
Michael Chanda53eca2009-03-27 17:46:36 -0700729 return mEnabled && mDependencyMet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 }
731
732 /**
733 * Sets whether this Preference is selectable.
734 *
735 * @param selectable Set true to make it selectable.
736 */
737 public void setSelectable(boolean selectable) {
738 if (mSelectable != selectable) {
739 mSelectable = selectable;
740 notifyChanged();
741 }
742 }
743
744 /**
745 * Checks whether this Preference should be selectable in the list.
746 *
747 * @return True if it is selectable, false otherwise.
748 */
749 public boolean isSelectable() {
750 return mSelectable;
751 }
752
753 /**
754 * Sets whether this Preference should disable its view when it gets
755 * disabled.
756 * <p>
757 * For example, set this and {@link #setEnabled(boolean)} to false for
758 * preferences that are only displaying information and 1) should not be
759 * clickable 2) should not have the view set to the disabled state.
760 *
761 * @param shouldDisableView Set true if this preference should disable its view
762 * when the preference is disabled.
763 */
764 public void setShouldDisableView(boolean shouldDisableView) {
765 mShouldDisableView = shouldDisableView;
766 notifyChanged();
767 }
768
769 /**
770 * Checks whether this Preference should disable its view when it's action is disabled.
771 * @see #setShouldDisableView(boolean)
772 * @return True if it should disable the view.
773 */
774 public boolean getShouldDisableView() {
775 return mShouldDisableView;
776 }
777
778 /**
779 * Returns a unique ID for this Preference. This ID should be unique across all
780 * Preference objects in a hierarchy.
781 *
782 * @return A unique ID for this Preference.
783 */
784 long getId() {
785 return mId;
786 }
787
788 /**
789 * Processes a click on the preference. This includes saving the value to
790 * the {@link SharedPreferences}. However, the overridden method should
791 * call {@link #callChangeListener(Object)} to make sure the client wants to
792 * update the preference's state with the new value.
793 */
794 protected void onClick() {
795 }
796
797 /**
798 * Sets the key for this Preference, which is used as a key to the
799 * {@link SharedPreferences}. This should be unique for the package.
800 *
801 * @param key The key for the preference.
802 */
803 public void setKey(String key) {
804 mKey = key;
805
806 if (mRequiresKey && !hasKey()) {
807 requireKey();
808 }
809 }
810
811 /**
812 * Gets the key for this Preference, which is also the key used for storing
813 * values into SharedPreferences.
814 *
815 * @return The key.
816 */
817 public String getKey() {
818 return mKey;
819 }
820
821 /**
822 * Checks whether the key is present, and if it isn't throws an
823 * exception. This should be called by subclasses that store preferences in
824 * the {@link SharedPreferences}.
825 *
826 * @throws IllegalStateException If there is no key assigned.
827 */
828 void requireKey() {
829 if (mKey == null) {
830 throw new IllegalStateException("Preference does not have a key assigned.");
831 }
832
833 mRequiresKey = true;
834 }
835
836 /**
837 * Checks whether this Preference has a valid key.
838 *
839 * @return True if the key exists and is not a blank string, false otherwise.
840 */
841 public boolean hasKey() {
842 return !TextUtils.isEmpty(mKey);
843 }
844
845 /**
846 * Checks whether this Preference is persistent. If it is, it stores its value(s) into
847 * the persistent {@link SharedPreferences} storage.
848 *
849 * @return True if it is persistent.
850 */
851 public boolean isPersistent() {
852 return mPersistent;
853 }
854
855 /**
856 * Checks whether, at the given time this method is called,
857 * this Preference should store/restore its value(s) into the
858 * {@link SharedPreferences}. This, at minimum, checks whether this
859 * Preference is persistent and it currently has a key. Before you
860 * save/restore from the {@link SharedPreferences}, check this first.
861 *
862 * @return True if it should persist the value.
863 */
864 protected boolean shouldPersist() {
865 return mPreferenceManager != null && isPersistent() && hasKey();
866 }
867
868 /**
869 * Sets whether this Preference is persistent. When persistent,
870 * it stores its value(s) into the persistent {@link SharedPreferences}
871 * storage.
872 *
873 * @param persistent Set true if it should store its value(s) into the {@link SharedPreferences}.
874 */
875 public void setPersistent(boolean persistent) {
876 mPersistent = persistent;
877 }
878
879 /**
880 * Call this method after the user changes the preference, but before the
881 * internal state is set. This allows the client to ignore the user value.
882 *
883 * @param newValue The new value of this Preference.
884 * @return True if the user value should be set as the preference
885 * value (and persisted).
886 */
887 protected boolean callChangeListener(Object newValue) {
888 return mOnChangeListener == null ? true : mOnChangeListener.onPreferenceChange(this, newValue);
889 }
890
891 /**
892 * Sets the callback to be invoked when this Preference is changed by the
893 * user (but before the internal state has been updated).
894 *
895 * @param onPreferenceChangeListener The callback to be invoked.
896 */
897 public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) {
898 mOnChangeListener = onPreferenceChangeListener;
899 }
900
901 /**
902 * Returns the callback to be invoked when this Preference is changed by the
903 * user (but before the internal state has been updated).
904 *
905 * @return The callback to be invoked.
906 */
907 public OnPreferenceChangeListener getOnPreferenceChangeListener() {
908 return mOnChangeListener;
909 }
910
911 /**
912 * Sets the callback to be invoked when this Preference is clicked.
913 *
914 * @param onPreferenceClickListener The callback to be invoked.
915 */
916 public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
917 mOnClickListener = onPreferenceClickListener;
918 }
919
920 /**
921 * Returns the callback to be invoked when this Preference is clicked.
922 *
923 * @return The callback to be invoked.
924 */
925 public OnPreferenceClickListener getOnPreferenceClickListener() {
926 return mOnClickListener;
927 }
928
929 /**
930 * Called when a click should be performed.
931 *
932 * @param preferenceScreen A {@link PreferenceScreen} whose hierarchy click
933 * listener should be called in the proper order (between other
934 * processing). May be null.
935 */
936 void performClick(PreferenceScreen preferenceScreen) {
937
938 if (!isEnabled()) {
939 return;
940 }
941
942 onClick();
943
944 if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) {
945 return;
946 }
947
948 PreferenceManager preferenceManager = getPreferenceManager();
949 if (preferenceManager != null) {
950 PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
951 .getOnPreferenceTreeClickListener();
952 if (preferenceScreen != null && listener != null
953 && listener.onPreferenceTreeClick(preferenceScreen, this)) {
954 return;
955 }
956 }
957
958 if (mIntent != null) {
959 Context context = getContext();
960 context.startActivity(mIntent);
961 }
962 }
John Reck014fea22011-06-15 16:46:36 -0700963
964 /**
965 * Allows a Preference to intercept key events without having focus.
966 * For example, SeekBarPreference uses this to intercept +/- to adjust
967 * the progress.
968 * @return True if the Preference handled the key. Returns false by default.
969 * @hide
970 */
971 public boolean onKey(View v, int keyCode, KeyEvent event) {
972 return false;
973 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974
975 /**
976 * Returns the {@link android.content.Context} of this Preference.
977 * Each Preference in a Preference hierarchy can be
978 * from different Context (for example, if multiple activities provide preferences into a single
979 * {@link PreferenceActivity}). This Context will be used to save the Preference values.
980 *
981 * @return The Context of this Preference.
982 */
983 public Context getContext() {
984 return mContext;
985 }
986
987 /**
988 * Returns the {@link SharedPreferences} where this Preference can read its
989 * value(s). Usually, it's easier to use one of the helper read methods:
990 * {@link #getPersistedBoolean(boolean)}, {@link #getPersistedFloat(float)},
991 * {@link #getPersistedInt(int)}, {@link #getPersistedLong(long)},
992 * {@link #getPersistedString(String)}. To save values, see
993 * {@link #getEditor()}.
994 * <p>
995 * In some cases, writes to the {@link #getEditor()} will not be committed
996 * right away and hence not show up in the returned
997 * {@link SharedPreferences}, this is intended behavior to improve
998 * performance.
999 *
1000 * @return The {@link SharedPreferences} where this Preference reads its
1001 * value(s), or null if it isn't attached to a Preference hierarchy.
1002 * @see #getEditor()
1003 */
1004 public SharedPreferences getSharedPreferences() {
1005 if (mPreferenceManager == null) {
1006 return null;
1007 }
1008
1009 return mPreferenceManager.getSharedPreferences();
1010 }
1011
1012 /**
1013 * Returns an {@link SharedPreferences.Editor} where this Preference can
1014 * save its value(s). Usually it's easier to use one of the helper save
1015 * methods: {@link #persistBoolean(boolean)}, {@link #persistFloat(float)},
1016 * {@link #persistInt(int)}, {@link #persistLong(long)},
1017 * {@link #persistString(String)}. To read values, see
1018 * {@link #getSharedPreferences()}. If {@link #shouldCommit()} returns
1019 * true, it is this Preference's responsibility to commit.
1020 * <p>
1021 * In some cases, writes to this will not be committed right away and hence
1022 * not show up in the SharedPreferences, this is intended behavior to
1023 * improve performance.
1024 *
1025 * @return A {@link SharedPreferences.Editor} where this preference saves
1026 * its value(s), or null if it isn't attached to a Preference
1027 * hierarchy.
1028 * @see #shouldCommit()
1029 * @see #getSharedPreferences()
1030 */
1031 public SharedPreferences.Editor getEditor() {
1032 if (mPreferenceManager == null) {
1033 return null;
1034 }
1035
1036 return mPreferenceManager.getEditor();
1037 }
1038
1039 /**
1040 * Returns whether the {@link Preference} should commit its saved value(s) in
1041 * {@link #getEditor()}. This may return false in situations where batch
1042 * committing is being done (by the manager) to improve performance.
1043 *
1044 * @return Whether the Preference should commit its saved value(s).
1045 * @see #getEditor()
1046 */
1047 public boolean shouldCommit() {
1048 if (mPreferenceManager == null) {
1049 return false;
1050 }
1051
1052 return mPreferenceManager.shouldCommit();
1053 }
1054
1055 /**
1056 * Compares Preference objects based on order (if set), otherwise alphabetically on the titles.
1057 *
1058 * @param another The Preference to compare to this one.
1059 * @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another</var>;
1060 * greater than 0 if this Preference sorts after <var>another</var>.
1061 */
1062 public int compareTo(Preference another) {
1063 if (mOrder != DEFAULT_ORDER
1064 || (mOrder == DEFAULT_ORDER && another.mOrder != DEFAULT_ORDER)) {
1065 // Do order comparison
1066 return mOrder - another.mOrder;
1067 } else if (mTitle == null) {
1068 return 1;
1069 } else if (another.mTitle == null) {
1070 return -1;
1071 } else {
1072 // Do name comparison
1073 return CharSequences.compareToIgnoreCase(mTitle, another.mTitle);
1074 }
1075 }
1076
1077 /**
1078 * Sets the internal change listener.
1079 *
1080 * @param listener The listener.
1081 * @see #notifyChanged()
1082 */
1083 final void setOnPreferenceChangeInternalListener(OnPreferenceChangeInternalListener listener) {
1084 mListener = listener;
1085 }
1086
1087 /**
1088 * Should be called when the data of this {@link Preference} has changed.
1089 */
1090 protected void notifyChanged() {
1091 if (mListener != null) {
1092 mListener.onPreferenceChange(this);
1093 }
1094 }
1095
1096 /**
1097 * Should be called when a Preference has been
1098 * added/removed from this group, or the ordering should be
1099 * re-evaluated.
1100 */
1101 protected void notifyHierarchyChanged() {
1102 if (mListener != null) {
1103 mListener.onPreferenceHierarchyChange(this);
1104 }
1105 }
1106
1107 /**
1108 * Gets the {@link PreferenceManager} that manages this Preference object's tree.
1109 *
1110 * @return The {@link PreferenceManager}.
1111 */
1112 public PreferenceManager getPreferenceManager() {
1113 return mPreferenceManager;
1114 }
1115
1116 /**
1117 * Called when this Preference has been attached to a Preference hierarchy.
1118 * Make sure to call the super implementation.
1119 *
1120 * @param preferenceManager The PreferenceManager of the hierarchy.
1121 */
1122 protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
1123 mPreferenceManager = preferenceManager;
1124
1125 mId = preferenceManager.getNextId();
1126
1127 dispatchSetInitialValue();
1128 }
1129
1130 /**
1131 * Called when the Preference hierarchy has been attached to the
1132 * {@link PreferenceActivity}. This can also be called when this
1133 * Preference has been attached to a group that was already attached
1134 * to the {@link PreferenceActivity}.
1135 */
1136 protected void onAttachedToActivity() {
1137 // At this point, the hierarchy that this preference is in is connected
1138 // with all other preferences.
1139 registerDependency();
1140 }
1141
1142 private void registerDependency() {
1143
1144 if (TextUtils.isEmpty(mDependencyKey)) return;
1145
1146 Preference preference = findPreferenceInHierarchy(mDependencyKey);
1147 if (preference != null) {
1148 preference.registerDependent(this);
1149 } else {
1150 throw new IllegalStateException("Dependency \"" + mDependencyKey
1151 + "\" not found for preference \"" + mKey + "\" (title: \"" + mTitle + "\"");
1152 }
1153 }
1154
1155 private void unregisterDependency() {
1156 if (mDependencyKey != null) {
1157 final Preference oldDependency = findPreferenceInHierarchy(mDependencyKey);
1158 if (oldDependency != null) {
1159 oldDependency.unregisterDependent(this);
1160 }
1161 }
1162 }
1163
1164 /**
1165 * Finds a Preference in this hierarchy (the whole thing,
1166 * even above/below your {@link PreferenceScreen} screen break) with the given
1167 * key.
1168 * <p>
1169 * This only functions after we have been attached to a hierarchy.
1170 *
1171 * @param key The key of the Preference to find.
1172 * @return The Preference that uses the given key.
1173 */
1174 protected Preference findPreferenceInHierarchy(String key) {
1175 if (TextUtils.isEmpty(key) || mPreferenceManager == null) {
1176 return null;
1177 }
1178
1179 return mPreferenceManager.findPreference(key);
1180 }
1181
1182 /**
1183 * Adds a dependent Preference on this Preference so we can notify it.
1184 * Usually, the dependent Preference registers itself (it's good for it to
1185 * know it depends on something), so please use
1186 * {@link Preference#setDependency(String)} on the dependent Preference.
1187 *
1188 * @param dependent The dependent Preference that will be enabled/disabled
1189 * according to the state of this Preference.
1190 */
1191 private void registerDependent(Preference dependent) {
1192 if (mDependents == null) {
1193 mDependents = new ArrayList<Preference>();
1194 }
1195
1196 mDependents.add(dependent);
1197
1198 dependent.onDependencyChanged(this, shouldDisableDependents());
1199 }
1200
1201 /**
1202 * Removes a dependent Preference on this Preference.
1203 *
1204 * @param dependent The dependent Preference that will be enabled/disabled
1205 * according to the state of this Preference.
1206 * @return Returns the same Preference object, for chaining multiple calls
1207 * into a single statement.
1208 */
1209 private void unregisterDependent(Preference dependent) {
1210 if (mDependents != null) {
1211 mDependents.remove(dependent);
1212 }
1213 }
1214
1215 /**
1216 * Notifies any listening dependents of a change that affects the
1217 * dependency.
1218 *
1219 * @param disableDependents Whether this Preference should disable
1220 * its dependents.
1221 */
1222 public void notifyDependencyChange(boolean disableDependents) {
1223 final List<Preference> dependents = mDependents;
1224
1225 if (dependents == null) {
1226 return;
1227 }
1228
1229 final int dependentsCount = dependents.size();
1230 for (int i = 0; i < dependentsCount; i++) {
1231 dependents.get(i).onDependencyChanged(this, disableDependents);
1232 }
1233 }
1234
1235 /**
1236 * Called when the dependency changes.
1237 *
1238 * @param dependency The Preference that this Preference depends on.
1239 * @param disableDependent Set true to disable this Preference.
1240 */
1241 public void onDependencyChanged(Preference dependency, boolean disableDependent) {
Michael Chanda53eca2009-03-27 17:46:36 -07001242 if (mDependencyMet == disableDependent) {
1243 mDependencyMet = !disableDependent;
1244
1245 // Enabled state can change dependent preferences' states, so notify
1246 notifyDependencyChange(shouldDisableDependents());
1247
1248 notifyChanged();
1249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 }
1251
1252 /**
1253 * Checks whether this preference's dependents should currently be
1254 * disabled.
1255 *
1256 * @return True if the dependents should be disabled, otherwise false.
1257 */
1258 public boolean shouldDisableDependents() {
1259 return !isEnabled();
1260 }
1261
1262 /**
1263 * Sets the key of a Preference that this Preference will depend on. If that
1264 * Preference is not set or is off, this Preference will be disabled.
1265 *
1266 * @param dependencyKey The key of the Preference that this depends on.
1267 */
1268 public void setDependency(String dependencyKey) {
1269 // Unregister the old dependency, if we had one
1270 unregisterDependency();
1271
1272 // Register the new
1273 mDependencyKey = dependencyKey;
1274 registerDependency();
1275 }
1276
1277 /**
1278 * Returns the key of the dependency on this Preference.
1279 *
1280 * @return The key of the dependency.
1281 * @see #setDependency(String)
1282 */
1283 public String getDependency() {
1284 return mDependencyKey;
1285 }
1286
1287 /**
1288 * Called when this Preference is being removed from the hierarchy. You
1289 * should remove any references to this Preference that you know about. Make
1290 * sure to call through to the superclass implementation.
1291 */
1292 protected void onPrepareForRemoval() {
1293 unregisterDependency();
1294 }
1295
1296 /**
1297 * Sets the default value for this Preference, which will be set either if
1298 * persistence is off or persistence is on and the preference is not found
1299 * in the persistent storage.
1300 *
1301 * @param defaultValue The default value.
1302 */
1303 public void setDefaultValue(Object defaultValue) {
1304 mDefaultValue = defaultValue;
1305 }
1306
1307 private void dispatchSetInitialValue() {
1308 // By now, we know if we are persistent.
1309 final boolean shouldPersist = shouldPersist();
1310 if (!shouldPersist || !getSharedPreferences().contains(mKey)) {
1311 if (mDefaultValue != null) {
1312 onSetInitialValue(false, mDefaultValue);
1313 }
1314 } else {
1315 onSetInitialValue(true, null);
1316 }
1317 }
1318
1319 /**
1320 * Implement this to set the initial value of the Preference.
1321 * <p>
1322 * If <var>restorePersistedValue</var> is true, you should restore the
1323 * Preference value from the {@link android.content.SharedPreferences}. If
1324 * <var>restorePersistedValue</var> is false, you should set the Preference
1325 * value to defaultValue that is given (and possibly store to SharedPreferences
1326 * if {@link #shouldPersist()} is true).
1327 * <p>
1328 * This may not always be called. One example is if it should not persist
1329 * but there is no default value given.
1330 *
1331 * @param restorePersistedValue True to restore the persisted value;
1332 * false to use the given <var>defaultValue</var>.
1333 * @param defaultValue The default value for this Preference. Only use this
1334 * if <var>restorePersistedValue</var> is false.
1335 */
1336 protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
1337 }
1338
1339 private void tryCommit(SharedPreferences.Editor editor) {
1340 if (mPreferenceManager.shouldCommit()) {
Brad Fitzpatrickdd644c12010-10-10 10:58:47 -07001341 try {
1342 editor.apply();
1343 } catch (AbstractMethodError unused) {
1344 // The app injected its own pre-Gingerbread
1345 // SharedPreferences.Editor implementation without
1346 // an apply method.
1347 editor.commit();
1348 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 }
1350 }
1351
1352 /**
1353 * Attempts to persist a String to the {@link android.content.SharedPreferences}.
1354 * <p>
1355 * This will check if this Preference is persistent, get an editor from
1356 * the {@link PreferenceManager}, put in the string, and check if we should commit (and
1357 * commit if so).
1358 *
1359 * @param value The value to persist.
1360 * @return True if the Preference is persistent. (This is not whether the
1361 * value was persisted, since we may not necessarily commit if there
1362 * will be a batch commit later.)
1363 * @see #getPersistedString(String)
1364 */
1365 protected boolean persistString(String value) {
1366 if (shouldPersist()) {
1367 // Shouldn't store null
1368 if (value == getPersistedString(null)) {
1369 // It's already there, so the same as persisting
1370 return true;
1371 }
1372
1373 SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1374 editor.putString(mKey, value);
1375 tryCommit(editor);
1376 return true;
1377 }
1378 return false;
1379 }
1380
1381 /**
1382 * Attempts to get a persisted String from the {@link android.content.SharedPreferences}.
1383 * <p>
1384 * This will check if this Preference is persistent, get the SharedPreferences
1385 * from the {@link PreferenceManager}, and get the value.
1386 *
1387 * @param defaultReturnValue The default value to return if either the
1388 * Preference is not persistent or the Preference is not in the
1389 * shared preferences.
1390 * @return The value from the SharedPreferences or the default return
1391 * value.
1392 * @see #persistString(String)
1393 */
1394 protected String getPersistedString(String defaultReturnValue) {
1395 if (!shouldPersist()) {
1396 return defaultReturnValue;
1397 }
1398
1399 return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue);
1400 }
1401
1402 /**
Adam Powell212db7d2010-04-08 16:24:46 -07001403 * Attempts to persist a set of Strings to the {@link android.content.SharedPreferences}.
1404 * <p>
1405 * This will check if this Preference is persistent, get an editor from
1406 * the {@link PreferenceManager}, put in the strings, and check if we should commit (and
1407 * commit if so).
1408 *
1409 * @param values The values to persist.
1410 * @return True if the Preference is persistent. (This is not whether the
1411 * value was persisted, since we may not necessarily commit if there
1412 * will be a batch commit later.)
1413 * @see #getPersistedString(Set)
1414 *
1415 * @hide Pending API approval
1416 */
1417 protected boolean persistStringSet(Set<String> values) {
1418 if (shouldPersist()) {
1419 // Shouldn't store null
1420 if (values.equals(getPersistedStringSet(null))) {
1421 // It's already there, so the same as persisting
1422 return true;
1423 }
1424
1425 SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1426 editor.putStringSet(mKey, values);
1427 tryCommit(editor);
1428 return true;
1429 }
1430 return false;
1431 }
1432
1433 /**
1434 * Attempts to get a persisted set of Strings from the
1435 * {@link android.content.SharedPreferences}.
1436 * <p>
1437 * This will check if this Preference is persistent, get the SharedPreferences
1438 * from the {@link PreferenceManager}, and get the value.
1439 *
1440 * @param defaultReturnValue The default value to return if either the
1441 * Preference is not persistent or the Preference is not in the
1442 * shared preferences.
1443 * @return The value from the SharedPreferences or the default return
1444 * value.
1445 * @see #persistStringSet(Set)
1446 *
1447 * @hide Pending API approval
1448 */
1449 protected Set<String> getPersistedStringSet(Set<String> defaultReturnValue) {
1450 if (!shouldPersist()) {
1451 return defaultReturnValue;
1452 }
1453
1454 return mPreferenceManager.getSharedPreferences().getStringSet(mKey, defaultReturnValue);
1455 }
1456
1457 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 * Attempts to persist an int to the {@link android.content.SharedPreferences}.
1459 *
1460 * @param value The value to persist.
1461 * @return True if the Preference is persistent. (This is not whether the
1462 * value was persisted, since we may not necessarily commit if there
1463 * will be a batch commit later.)
1464 * @see #persistString(String)
1465 * @see #getPersistedInt(int)
1466 */
1467 protected boolean persistInt(int value) {
1468 if (shouldPersist()) {
1469 if (value == getPersistedInt(~value)) {
1470 // It's already there, so the same as persisting
1471 return true;
1472 }
1473
1474 SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1475 editor.putInt(mKey, value);
1476 tryCommit(editor);
1477 return true;
1478 }
1479 return false;
1480 }
1481
1482 /**
1483 * Attempts to get a persisted int from the {@link android.content.SharedPreferences}.
1484 *
1485 * @param defaultReturnValue The default value to return if either this
1486 * Preference is not persistent or this Preference is not in the
1487 * SharedPreferences.
1488 * @return The value from the SharedPreferences or the default return
1489 * value.
1490 * @see #getPersistedString(String)
1491 * @see #persistInt(int)
1492 */
1493 protected int getPersistedInt(int defaultReturnValue) {
1494 if (!shouldPersist()) {
1495 return defaultReturnValue;
1496 }
1497
1498 return mPreferenceManager.getSharedPreferences().getInt(mKey, defaultReturnValue);
1499 }
1500
1501 /**
1502 * Attempts to persist a float to the {@link android.content.SharedPreferences}.
1503 *
1504 * @param value The value to persist.
1505 * @return True if this Preference is persistent. (This is not whether the
1506 * value was persisted, since we may not necessarily commit if there
1507 * will be a batch commit later.)
1508 * @see #persistString(String)
1509 * @see #getPersistedFloat(float)
1510 */
1511 protected boolean persistFloat(float value) {
1512 if (shouldPersist()) {
1513 if (value == getPersistedFloat(Float.NaN)) {
1514 // It's already there, so the same as persisting
1515 return true;
1516 }
1517
1518 SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1519 editor.putFloat(mKey, value);
1520 tryCommit(editor);
1521 return true;
1522 }
1523 return false;
1524 }
1525
1526 /**
1527 * Attempts to get a persisted float from the {@link android.content.SharedPreferences}.
1528 *
1529 * @param defaultReturnValue The default value to return if either this
1530 * Preference is not persistent or this Preference is not in the
1531 * SharedPreferences.
1532 * @return The value from the SharedPreferences or the default return
1533 * value.
1534 * @see #getPersistedString(String)
1535 * @see #persistFloat(float)
1536 */
1537 protected float getPersistedFloat(float defaultReturnValue) {
1538 if (!shouldPersist()) {
1539 return defaultReturnValue;
1540 }
1541
1542 return mPreferenceManager.getSharedPreferences().getFloat(mKey, defaultReturnValue);
1543 }
1544
1545 /**
1546 * Attempts to persist a long to the {@link android.content.SharedPreferences}.
1547 *
1548 * @param value The value to persist.
1549 * @return True if this Preference is persistent. (This is not whether the
1550 * value was persisted, since we may not necessarily commit if there
1551 * will be a batch commit later.)
1552 * @see #persistString(String)
1553 * @see #getPersistedLong(long)
1554 */
1555 protected boolean persistLong(long value) {
1556 if (shouldPersist()) {
1557 if (value == getPersistedLong(~value)) {
1558 // It's already there, so the same as persisting
1559 return true;
1560 }
1561
1562 SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1563 editor.putLong(mKey, value);
1564 tryCommit(editor);
1565 return true;
1566 }
1567 return false;
1568 }
1569
1570 /**
1571 * Attempts to get a persisted long from the {@link android.content.SharedPreferences}.
1572 *
1573 * @param defaultReturnValue The default value to return if either this
1574 * Preference is not persistent or this Preference is not in the
1575 * SharedPreferences.
1576 * @return The value from the SharedPreferences or the default return
1577 * value.
1578 * @see #getPersistedString(String)
1579 * @see #persistLong(long)
1580 */
1581 protected long getPersistedLong(long defaultReturnValue) {
1582 if (!shouldPersist()) {
1583 return defaultReturnValue;
1584 }
1585
1586 return mPreferenceManager.getSharedPreferences().getLong(mKey, defaultReturnValue);
1587 }
1588
1589 /**
1590 * Attempts to persist a boolean to the {@link android.content.SharedPreferences}.
1591 *
1592 * @param value The value to persist.
1593 * @return True if this Preference is persistent. (This is not whether the
1594 * value was persisted, since we may not necessarily commit if there
1595 * will be a batch commit later.)
1596 * @see #persistString(String)
1597 * @see #getPersistedBoolean(boolean)
1598 */
1599 protected boolean persistBoolean(boolean value) {
1600 if (shouldPersist()) {
1601 if (value == getPersistedBoolean(!value)) {
1602 // It's already there, so the same as persisting
1603 return true;
1604 }
1605
1606 SharedPreferences.Editor editor = mPreferenceManager.getEditor();
1607 editor.putBoolean(mKey, value);
1608 tryCommit(editor);
1609 return true;
1610 }
1611 return false;
1612 }
1613
1614 /**
1615 * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}.
1616 *
1617 * @param defaultReturnValue The default value to return if either this
1618 * Preference is not persistent or this Preference is not in the
1619 * SharedPreferences.
1620 * @return The value from the SharedPreferences or the default return
1621 * value.
1622 * @see #getPersistedString(String)
1623 * @see #persistBoolean(boolean)
1624 */
1625 protected boolean getPersistedBoolean(boolean defaultReturnValue) {
1626 if (!shouldPersist()) {
1627 return defaultReturnValue;
1628 }
1629
1630 return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue);
1631 }
1632
1633 boolean hasSpecifiedLayout() {
1634 return mHasSpecifiedLayout;
1635 }
1636
1637 @Override
1638 public String toString() {
1639 return getFilterableStringBuilder().toString();
1640 }
1641
1642 /**
1643 * Returns the text that will be used to filter this Preference depending on
1644 * user input.
1645 * <p>
1646 * If overridding and calling through to the superclass, make sure to prepend
1647 * your additions with a space.
1648 *
1649 * @return Text as a {@link StringBuilder} that will be used to filter this
1650 * preference. By default, this is the title and summary
1651 * (concatenated with a space).
1652 */
1653 StringBuilder getFilterableStringBuilder() {
1654 StringBuilder sb = new StringBuilder();
1655 CharSequence title = getTitle();
1656 if (!TextUtils.isEmpty(title)) {
1657 sb.append(title).append(' ');
1658 }
1659 CharSequence summary = getSummary();
1660 if (!TextUtils.isEmpty(summary)) {
1661 sb.append(summary).append(' ');
1662 }
Tammo Spalink0bb99602009-09-08 18:30:33 +08001663 if (sb.length() > 0) {
1664 // Drop the last space
1665 sb.setLength(sb.length() - 1);
1666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 return sb;
1668 }
1669
1670 /**
1671 * Store this Preference hierarchy's frozen state into the given container.
1672 *
1673 * @param container The Bundle in which to save the instance of this Preference.
1674 *
1675 * @see #restoreHierarchyState
1676 * @see #onSaveInstanceState
1677 */
1678 public void saveHierarchyState(Bundle container) {
1679 dispatchSaveInstanceState(container);
1680 }
1681
1682 /**
1683 * Called by {@link #saveHierarchyState} to store the instance for this Preference and its children.
1684 * May be overridden to modify how the save happens for children. For example, some
1685 * Preference objects may want to not store an instance for their children.
1686 *
1687 * @param container The Bundle in which to save the instance of this Preference.
1688 *
1689 * @see #saveHierarchyState
1690 * @see #onSaveInstanceState
1691 */
1692 void dispatchSaveInstanceState(Bundle container) {
1693 if (hasKey()) {
1694 mBaseMethodCalled = false;
1695 Parcelable state = onSaveInstanceState();
1696 if (!mBaseMethodCalled) {
1697 throw new IllegalStateException(
1698 "Derived class did not call super.onSaveInstanceState()");
1699 }
1700 if (state != null) {
1701 container.putParcelable(mKey, state);
1702 }
1703 }
1704 }
1705
1706 /**
1707 * Hook allowing a Preference to generate a representation of its internal
1708 * state that can later be used to create a new instance with that same
1709 * state. This state should only contain information that is not persistent
1710 * or can be reconstructed later.
1711 *
1712 * @return A Parcelable object containing the current dynamic state of
1713 * this Preference, or null if there is nothing interesting to save.
1714 * The default implementation returns null.
1715 * @see #onRestoreInstanceState
1716 * @see #saveHierarchyState
1717 */
1718 protected Parcelable onSaveInstanceState() {
1719 mBaseMethodCalled = true;
1720 return BaseSavedState.EMPTY_STATE;
1721 }
1722
1723 /**
1724 * Restore this Preference hierarchy's previously saved state from the given container.
1725 *
1726 * @param container The Bundle that holds the previously saved state.
1727 *
1728 * @see #saveHierarchyState
1729 * @see #onRestoreInstanceState
1730 */
1731 public void restoreHierarchyState(Bundle container) {
1732 dispatchRestoreInstanceState(container);
1733 }
1734
1735 /**
1736 * Called by {@link #restoreHierarchyState} to retrieve the saved state for this
1737 * Preference and its children. May be overridden to modify how restoring
1738 * happens to the children of a Preference. For example, some Preference objects may
1739 * not want to save state for their children.
1740 *
1741 * @param container The Bundle that holds the previously saved state.
1742 * @see #restoreHierarchyState
1743 * @see #onRestoreInstanceState
1744 */
1745 void dispatchRestoreInstanceState(Bundle container) {
1746 if (hasKey()) {
1747 Parcelable state = container.getParcelable(mKey);
1748 if (state != null) {
1749 mBaseMethodCalled = false;
1750 onRestoreInstanceState(state);
1751 if (!mBaseMethodCalled) {
1752 throw new IllegalStateException(
1753 "Derived class did not call super.onRestoreInstanceState()");
1754 }
1755 }
1756 }
1757 }
1758
1759 /**
1760 * Hook allowing a Preference to re-apply a representation of its internal
1761 * state that had previously been generated by {@link #onSaveInstanceState}.
1762 * This function will never be called with a null state.
1763 *
1764 * @param state The saved state that had previously been returned by
1765 * {@link #onSaveInstanceState}.
1766 * @see #onSaveInstanceState
1767 * @see #restoreHierarchyState
1768 */
1769 protected void onRestoreInstanceState(Parcelable state) {
1770 mBaseMethodCalled = true;
1771 if (state != BaseSavedState.EMPTY_STATE && state != null) {
1772 throw new IllegalArgumentException("Wrong state class -- expecting Preference State");
1773 }
1774 }
1775
1776 /**
1777 * A base class for managing the instance state of a {@link Preference}.
1778 */
1779 public static class BaseSavedState extends AbsSavedState {
1780 public BaseSavedState(Parcel source) {
1781 super(source);
1782 }
1783
1784 public BaseSavedState(Parcelable superState) {
1785 super(superState);
1786 }
1787
1788 public static final Parcelable.Creator<BaseSavedState> CREATOR =
1789 new Parcelable.Creator<BaseSavedState>() {
1790 public BaseSavedState createFromParcel(Parcel in) {
1791 return new BaseSavedState(in);
1792 }
1793
1794 public BaseSavedState[] newArray(int size) {
1795 return new BaseSavedState[size];
1796 }
1797 };
1798 }
1799
1800}