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