1 /* 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 17 package android.preference; 18 19 import android.annotation.CallSuper; 20 import android.annotation.DrawableRes; 21 import android.annotation.LayoutRes; 22 import android.annotation.Nullable; 23 import android.annotation.StringRes; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.SharedPreferences; 28 import android.content.res.TypedArray; 29 import android.graphics.drawable.Drawable; 30 import android.os.Build; 31 import android.os.Bundle; 32 import android.os.Parcel; 33 import android.os.Parcelable; 34 import android.text.TextUtils; 35 import android.util.AttributeSet; 36 import android.view.AbsSavedState; 37 import android.view.KeyEvent; 38 import android.view.LayoutInflater; 39 import android.view.View; 40 import android.view.ViewGroup; 41 import android.widget.ImageView; 42 import android.widget.ListView; 43 import android.widget.TextView; 44 45 import com.android.internal.util.CharSequences; 46 47 import java.util.ArrayList; 48 import java.util.List; 49 import java.util.Set; 50 51 /** 52 * Represents the basic Preference UI building 53 * block displayed by a {@link PreferenceActivity} in the form of a 54 * {@link ListView}. This class provides the {@link View} to be displayed in 55 * the activity and associates with a {@link SharedPreferences} to 56 * store/retrieve the preference data. 57 * <p> 58 * When specifying a preference hierarchy in XML, each element can point to a 59 * subclass of {@link Preference}, similar to the view hierarchy and layouts. 60 * <p> 61 * This class contains a {@code key} that will be used as the key into the 62 * {@link SharedPreferences}. It is up to the subclass to decide how to store 63 * the value. 64 * 65 * <div class="special reference"> 66 * <h3>Developer Guides</h3> 67 * <p>For information about building a settings UI with Preferences, 68 * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a> 69 * guide.</p> 70 * </div> 71 * 72 * @attr ref android.R.styleable#Preference_icon 73 * @attr ref android.R.styleable#Preference_key 74 * @attr ref android.R.styleable#Preference_title 75 * @attr ref android.R.styleable#Preference_summary 76 * @attr ref android.R.styleable#Preference_order 77 * @attr ref android.R.styleable#Preference_fragment 78 * @attr ref android.R.styleable#Preference_layout 79 * @attr ref android.R.styleable#Preference_widgetLayout 80 * @attr ref android.R.styleable#Preference_enabled 81 * @attr ref android.R.styleable#Preference_selectable 82 * @attr ref android.R.styleable#Preference_dependency 83 * @attr ref android.R.styleable#Preference_persistent 84 * @attr ref android.R.styleable#Preference_defaultValue 85 * @attr ref android.R.styleable#Preference_shouldDisableView 86 * @attr ref android.R.styleable#Preference_recycleEnabled 87 * @attr ref android.R.styleable#Preference_singleLineTitle 88 * @attr ref android.R.styleable#Preference_iconSpaceReserved 89 * 90 * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> 91 * <a href="{@docRoot}reference/androidx/preference/package-summary.html"> 92 * Preference Library</a> for consistent behavior across all devices. For more information on 93 * using the AndroidX Preference Library see 94 * <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>. 95 */ 96 @Deprecated 97 public class Preference implements Comparable<Preference> { 98 /** 99 * Specify for {@link #setOrder(int)} if a specific order is not required. 100 */ 101 public static final int DEFAULT_ORDER = Integer.MAX_VALUE; 102 103 private Context mContext; 104 105 @Nullable 106 private PreferenceManager mPreferenceManager; 107 108 /** 109 * The data store that should be used by this Preference to store / retrieve data. If null then 110 * {@link PreferenceManager#getPreferenceDataStore()} needs to be checked. If that one is null 111 * too it means that we are using {@link android.content.SharedPreferences} to store the data. 112 */ 113 @Nullable 114 private PreferenceDataStore mPreferenceDataStore; 115 116 /** 117 * Set when added to hierarchy since we need a unique ID within that 118 * hierarchy. 119 */ 120 private long mId; 121 122 private OnPreferenceChangeListener mOnChangeListener; 123 private OnPreferenceClickListener mOnClickListener; 124 125 private int mOrder = DEFAULT_ORDER; 126 private CharSequence mTitle; 127 private int mTitleRes; 128 @UnsupportedAppUsage 129 private CharSequence mSummary; 130 /** 131 * mIconResId is overridden by mIcon, if mIcon is specified. 132 */ 133 private int mIconResId; 134 private Drawable mIcon; 135 private String mKey; 136 private Intent mIntent; 137 private String mFragment; 138 private Bundle mExtras; 139 private boolean mEnabled = true; 140 private boolean mSelectable = true; 141 private boolean mRequiresKey; 142 private boolean mPersistent = true; 143 private String mDependencyKey; 144 private Object mDefaultValue; 145 private boolean mDependencyMet = true; 146 private boolean mParentDependencyMet = true; 147 private boolean mRecycleEnabled = true; 148 private boolean mHasSingleLineTitleAttr; 149 private boolean mSingleLineTitle = true; 150 private boolean mIconSpaceReserved; 151 152 /** 153 * @see #setShouldDisableView(boolean) 154 */ 155 private boolean mShouldDisableView = true; 156 157 @UnsupportedAppUsage 158 private int mLayoutResId = com.android.internal.R.layout.preference; 159 @UnsupportedAppUsage 160 private int mWidgetLayoutResId; 161 162 private OnPreferenceChangeInternalListener mListener; 163 164 private List<Preference> mDependents; 165 166 private PreferenceGroup mParentGroup; 167 168 private boolean mBaseMethodCalled; 169 170 /** 171 * Interface definition for a callback to be invoked when the value of this 172 * {@link Preference} has been changed by the user and is 173 * about to be set and/or persisted. This gives the client a chance 174 * to prevent setting and/or persisting the value. 175 * 176 * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> 177 * <a href="{@docRoot}reference/androidx/preference/package-summary.html"> 178 * Preference Library</a> for consistent behavior across all devices. 179 * For more information on using the AndroidX Preference Library see 180 * <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>. 181 */ 182 @Deprecated 183 public interface OnPreferenceChangeListener { 184 /** 185 * Called when a Preference has been changed by the user. This is 186 * called before the state of the Preference is about to be updated and 187 * before the state is persisted. 188 * 189 * @param preference The changed Preference. 190 * @param newValue The new value of the Preference. 191 * @return True to update the state of the Preference with the new value. 192 */ onPreferenceChange(Preference preference, Object newValue)193 boolean onPreferenceChange(Preference preference, Object newValue); 194 } 195 196 /** 197 * Interface definition for a callback to be invoked when a {@link Preference} is 198 * clicked. 199 * 200 * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> 201 * <a href="{@docRoot}reference/androidx/preference/package-summary.html"> 202 * Preference Library</a> for consistent behavior across all devices. 203 * For more information on using the AndroidX Preference Library see 204 * <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>. 205 */ 206 @Deprecated 207 public interface OnPreferenceClickListener { 208 /** 209 * Called when a Preference has been clicked. 210 * 211 * @param preference The Preference that was clicked. 212 * @return True if the click was handled. 213 */ onPreferenceClick(Preference preference)214 boolean onPreferenceClick(Preference preference); 215 } 216 217 /** 218 * Interface definition for a callback to be invoked when this 219 * {@link Preference} is changed or, if this is a group, there is an 220 * addition/removal of {@link Preference}(s). This is used internally. 221 */ 222 interface OnPreferenceChangeInternalListener { 223 /** 224 * Called when this Preference has changed. 225 * 226 * @param preference This preference. 227 */ onPreferenceChange(Preference preference)228 void onPreferenceChange(Preference preference); 229 230 /** 231 * Called when this group has added/removed {@link Preference}(s). 232 * 233 * @param preference This Preference. 234 */ onPreferenceHierarchyChange(Preference preference)235 void onPreferenceHierarchyChange(Preference preference); 236 } 237 238 /** 239 * Perform inflation from XML and apply a class-specific base style. This 240 * constructor of Preference allows subclasses to use their own base style 241 * when they are inflating. For example, a {@link CheckBoxPreference} 242 * constructor calls this version of the super class constructor and 243 * supplies {@code android.R.attr.checkBoxPreferenceStyle} for 244 * <var>defStyleAttr</var>. This allows the theme's checkbox preference 245 * style to modify all of the base preference attributes as well as the 246 * {@link CheckBoxPreference} class's attributes. 247 * 248 * @param context The Context this is associated with, through which it can 249 * access the current theme, resources, 250 * {@link SharedPreferences}, etc. 251 * @param attrs The attributes of the XML tag that is inflating the 252 * preference. 253 * @param defStyleAttr An attribute in the current theme that contains a 254 * reference to a style resource that supplies default values for 255 * the view. Can be 0 to not look for defaults. 256 * @param defStyleRes A resource identifier of a style resource that 257 * supplies default values for the view, used only if 258 * defStyleAttr is 0 or can not be found in the theme. Can be 0 259 * to not look for defaults. 260 * @see #Preference(Context, AttributeSet) 261 */ Preference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)262 public Preference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 263 mContext = context; 264 265 final TypedArray a = context.obtainStyledAttributes( 266 attrs, com.android.internal.R.styleable.Preference, defStyleAttr, defStyleRes); 267 for (int i = a.getIndexCount() - 1; i >= 0; i--) { 268 int attr = a.getIndex(i); 269 switch (attr) { 270 case com.android.internal.R.styleable.Preference_icon: 271 mIconResId = a.getResourceId(attr, 0); 272 break; 273 274 case com.android.internal.R.styleable.Preference_key: 275 mKey = a.getString(attr); 276 break; 277 278 case com.android.internal.R.styleable.Preference_title: 279 mTitleRes = a.getResourceId(attr, 0); 280 mTitle = a.getText(attr); 281 break; 282 283 case com.android.internal.R.styleable.Preference_summary: 284 mSummary = a.getText(attr); 285 break; 286 287 case com.android.internal.R.styleable.Preference_order: 288 mOrder = a.getInt(attr, mOrder); 289 break; 290 291 case com.android.internal.R.styleable.Preference_fragment: 292 mFragment = a.getString(attr); 293 break; 294 295 case com.android.internal.R.styleable.Preference_layout: 296 mLayoutResId = a.getResourceId(attr, mLayoutResId); 297 break; 298 299 case com.android.internal.R.styleable.Preference_widgetLayout: 300 mWidgetLayoutResId = a.getResourceId(attr, mWidgetLayoutResId); 301 break; 302 303 case com.android.internal.R.styleable.Preference_enabled: 304 mEnabled = a.getBoolean(attr, true); 305 break; 306 307 case com.android.internal.R.styleable.Preference_selectable: 308 mSelectable = a.getBoolean(attr, true); 309 break; 310 311 case com.android.internal.R.styleable.Preference_persistent: 312 mPersistent = a.getBoolean(attr, mPersistent); 313 break; 314 315 case com.android.internal.R.styleable.Preference_dependency: 316 mDependencyKey = a.getString(attr); 317 break; 318 319 case com.android.internal.R.styleable.Preference_defaultValue: 320 mDefaultValue = onGetDefaultValue(a, attr); 321 break; 322 323 case com.android.internal.R.styleable.Preference_shouldDisableView: 324 mShouldDisableView = a.getBoolean(attr, mShouldDisableView); 325 break; 326 327 case com.android.internal.R.styleable.Preference_recycleEnabled: 328 mRecycleEnabled = a.getBoolean(attr, mRecycleEnabled); 329 break; 330 331 case com.android.internal.R.styleable.Preference_singleLineTitle: 332 mSingleLineTitle = a.getBoolean(attr, mSingleLineTitle); 333 mHasSingleLineTitleAttr = true; 334 break; 335 336 case com.android.internal.R.styleable.Preference_iconSpaceReserved: 337 mIconSpaceReserved = a.getBoolean(attr, mIconSpaceReserved); 338 break; 339 } 340 } 341 a.recycle(); 342 } 343 344 /** 345 * Perform inflation from XML and apply a class-specific base style. This 346 * constructor of Preference allows subclasses to use their own base style 347 * when they are inflating. For example, a {@link CheckBoxPreference} 348 * constructor calls this version of the super class constructor and 349 * supplies {@code android.R.attr.checkBoxPreferenceStyle} for 350 * <var>defStyleAttr</var>. This allows the theme's checkbox preference 351 * style to modify all of the base preference attributes as well as the 352 * {@link CheckBoxPreference} class's attributes. 353 * 354 * @param context The Context this is associated with, through which it can 355 * access the current theme, resources, 356 * {@link SharedPreferences}, etc. 357 * @param attrs The attributes of the XML tag that is inflating the 358 * preference. 359 * @param defStyleAttr An attribute in the current theme that contains a 360 * reference to a style resource that supplies default values for 361 * the view. Can be 0 to not look for defaults. 362 * @see #Preference(Context, AttributeSet) 363 */ Preference(Context context, AttributeSet attrs, int defStyleAttr)364 public Preference(Context context, AttributeSet attrs, int defStyleAttr) { 365 this(context, attrs, defStyleAttr, 0); 366 } 367 368 /** 369 * Constructor that is called when inflating a Preference from XML. This is 370 * called when a Preference is being constructed from an XML file, supplying 371 * attributes that were specified in the XML file. This version uses a 372 * default style of 0, so the only attribute values applied are those in the 373 * Context's Theme and the given AttributeSet. 374 * 375 * @param context The Context this is associated with, through which it can 376 * access the current theme, resources, {@link SharedPreferences}, 377 * etc. 378 * @param attrs The attributes of the XML tag that is inflating the 379 * preference. 380 * @see #Preference(Context, AttributeSet, int) 381 */ Preference(Context context, AttributeSet attrs)382 public Preference(Context context, AttributeSet attrs) { 383 this(context, attrs, com.android.internal.R.attr.preferenceStyle); 384 } 385 386 /** 387 * Constructor to create a Preference. 388 * 389 * @param context The Context in which to store Preference values. 390 */ Preference(Context context)391 public Preference(Context context) { 392 this(context, null); 393 } 394 395 /** 396 * Called when a Preference is being inflated and the default value 397 * attribute needs to be read. Since different Preference types have 398 * different value types, the subclass should get and return the default 399 * value which will be its value type. 400 * <p> 401 * For example, if the value type is String, the body of the method would 402 * proxy to {@link TypedArray#getString(int)}. 403 * 404 * @param a The set of attributes. 405 * @param index The index of the default value attribute. 406 * @return The default value of this preference type. 407 */ onGetDefaultValue(TypedArray a, int index)408 protected Object onGetDefaultValue(TypedArray a, int index) { 409 return null; 410 } 411 412 /** 413 * Sets an {@link Intent} to be used for 414 * {@link Context#startActivity(Intent)} when this Preference is clicked. 415 * 416 * @param intent The intent associated with this Preference. 417 */ setIntent(Intent intent)418 public void setIntent(Intent intent) { 419 mIntent = intent; 420 } 421 422 /** 423 * Return the {@link Intent} associated with this Preference. 424 * 425 * @return The {@link Intent} last set via {@link #setIntent(Intent)} or XML. 426 */ getIntent()427 public Intent getIntent() { 428 return mIntent; 429 } 430 431 /** 432 * Sets the class name of a fragment to be shown when this Preference is clicked. 433 * 434 * @param fragment The class name of the fragment associated with this Preference. 435 */ setFragment(String fragment)436 public void setFragment(String fragment) { 437 mFragment = fragment; 438 } 439 440 /** 441 * Return the fragment class name associated with this Preference. 442 * 443 * @return The fragment class name last set via {@link #setFragment} or XML. 444 */ getFragment()445 public String getFragment() { 446 return mFragment; 447 } 448 449 /** 450 * Sets a {@link PreferenceDataStore} to be used by this Preference instead of using 451 * {@link android.content.SharedPreferences}. 452 * 453 * <p>The data store will remain assigned even if the Preference is moved around the preference 454 * hierarchy. It will also override a data store propagated from the {@link PreferenceManager} 455 * that owns this Preference. 456 * 457 * @param dataStore The {@link PreferenceDataStore} to be used by this Preference. 458 * @see PreferenceManager#setPreferenceDataStore(PreferenceDataStore) 459 */ setPreferenceDataStore(PreferenceDataStore dataStore)460 public void setPreferenceDataStore(PreferenceDataStore dataStore) { 461 mPreferenceDataStore = dataStore; 462 } 463 464 /** 465 * Returns {@link PreferenceDataStore} used by this Preference. Returns {@code null} if 466 * {@link android.content.SharedPreferences} is used instead. 467 * 468 * <p>By default preferences always use {@link android.content.SharedPreferences}. To make this 469 * preference to use the {@link PreferenceDataStore} you need to assign your implementation 470 * to the Preference itself via {@link #setPreferenceDataStore(PreferenceDataStore)} or to its 471 * {@link PreferenceManager} via 472 * {@link PreferenceManager#setPreferenceDataStore(PreferenceDataStore)}. 473 * 474 * @return The {@link PreferenceDataStore} used by this Preference or {@code null} if none. 475 */ 476 @Nullable getPreferenceDataStore()477 public PreferenceDataStore getPreferenceDataStore() { 478 if (mPreferenceDataStore != null) { 479 return mPreferenceDataStore; 480 } else if (mPreferenceManager != null) { 481 return mPreferenceManager.getPreferenceDataStore(); 482 } 483 484 return null; 485 } 486 487 /** 488 * Return the extras Bundle object associated with this preference, creating 489 * a new Bundle if there currently isn't one. You can use this to get and 490 * set individual extra key/value pairs. 491 */ getExtras()492 public Bundle getExtras() { 493 if (mExtras == null) { 494 mExtras = new Bundle(); 495 } 496 return mExtras; 497 } 498 499 /** 500 * Return the extras Bundle object associated with this preference, returning {@code null} if 501 * there is not currently one. 502 */ peekExtras()503 public Bundle peekExtras() { 504 return mExtras; 505 } 506 507 /** 508 * Sets the layout resource that is inflated as the {@link View} to be shown 509 * for this Preference. In most cases, the default layout is sufficient for 510 * custom Preference objects and only the widget layout needs to be changed. 511 * <p> 512 * This layout should contain a {@link ViewGroup} with ID 513 * {@link android.R.id#widget_frame} to be the parent of the specific widget 514 * for this Preference. It should similarly contain 515 * {@link android.R.id#title} and {@link android.R.id#summary}. 516 * 517 * @param layoutResId The layout resource ID to be inflated and returned as 518 * a {@link View}. 519 * @see #setWidgetLayoutResource(int) 520 */ setLayoutResource(@ayoutRes int layoutResId)521 public void setLayoutResource(@LayoutRes int layoutResId) { 522 if (layoutResId != mLayoutResId) { 523 // Layout changed 524 mRecycleEnabled = false; 525 } 526 527 mLayoutResId = layoutResId; 528 } 529 530 /** 531 * Gets the layout resource that will be shown as the {@link View} for this Preference. 532 * 533 * @return The layout resource ID. 534 */ 535 @LayoutRes getLayoutResource()536 public int getLayoutResource() { 537 return mLayoutResId; 538 } 539 540 /** 541 * Sets the layout for the controllable widget portion of this Preference. This 542 * is inflated into the main layout. For example, a {@link CheckBoxPreference} 543 * would specify a custom layout (consisting of just the CheckBox) here, 544 * instead of creating its own main layout. 545 * 546 * @param widgetLayoutResId The layout resource ID to be inflated into the 547 * main layout. 548 * @see #setLayoutResource(int) 549 */ setWidgetLayoutResource(@ayoutRes int widgetLayoutResId)550 public void setWidgetLayoutResource(@LayoutRes int widgetLayoutResId) { 551 if (widgetLayoutResId != mWidgetLayoutResId) { 552 // Layout changed 553 mRecycleEnabled = false; 554 } 555 mWidgetLayoutResId = widgetLayoutResId; 556 } 557 558 /** 559 * Gets the layout resource for the controllable widget portion of this Preference. 560 * 561 * @return The layout resource ID. 562 */ 563 @LayoutRes getWidgetLayoutResource()564 public int getWidgetLayoutResource() { 565 return mWidgetLayoutResId; 566 } 567 568 /** 569 * Gets the View that will be shown in the {@link PreferenceActivity}. 570 * 571 * @param convertView The old View to reuse, if possible. Note: You should 572 * check that this View is non-null and of an appropriate type 573 * before using. If it is not possible to convert this View to 574 * display the correct data, this method can create a new View. 575 * @param parent The parent that this View will eventually be attached to. 576 * @return Returns the same Preference object, for chaining multiple calls 577 * into a single statement. 578 * @see #onCreateView(ViewGroup) 579 * @see #onBindView(View) 580 */ getView(View convertView, ViewGroup parent)581 public View getView(View convertView, ViewGroup parent) { 582 if (convertView == null) { 583 convertView = onCreateView(parent); 584 } 585 onBindView(convertView); 586 return convertView; 587 } 588 589 /** 590 * Creates the View to be shown for this Preference in the 591 * {@link PreferenceActivity}. The default behavior is to inflate the main 592 * layout of this Preference (see {@link #setLayoutResource(int)}. If 593 * changing this behavior, please specify a {@link ViewGroup} with ID 594 * {@link android.R.id#widget_frame}. 595 * <p> 596 * Make sure to call through to the superclass's implementation. 597 * 598 * @param parent The parent that this View will eventually be attached to. 599 * @return The View that displays this Preference. 600 * @see #onBindView(View) 601 */ 602 @CallSuper onCreateView(ViewGroup parent)603 protected View onCreateView(ViewGroup parent) { 604 final LayoutInflater layoutInflater = 605 (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 606 607 final View layout = layoutInflater.inflate(mLayoutResId, parent, false); 608 609 final ViewGroup widgetFrame = (ViewGroup) layout 610 .findViewById(com.android.internal.R.id.widget_frame); 611 if (widgetFrame != null) { 612 if (mWidgetLayoutResId != 0) { 613 layoutInflater.inflate(mWidgetLayoutResId, widgetFrame); 614 } else { 615 widgetFrame.setVisibility(View.GONE); 616 } 617 } 618 return layout; 619 } 620 621 /** 622 * Binds the created View to the data for this Preference. 623 * <p> 624 * This is a good place to grab references to custom Views in the layout and 625 * set properties on them. 626 * <p> 627 * Make sure to call through to the superclass's implementation. 628 * 629 * @param view The View that shows this Preference. 630 * @see #onCreateView(ViewGroup) 631 */ 632 @CallSuper onBindView(View view)633 protected void onBindView(View view) { 634 final TextView titleView = (TextView) view.findViewById(com.android.internal.R.id.title); 635 if (titleView != null) { 636 final CharSequence title = getTitle(); 637 if (!TextUtils.isEmpty(title)) { 638 titleView.setText(title); 639 titleView.setVisibility(View.VISIBLE); 640 if (mHasSingleLineTitleAttr) { 641 titleView.setSingleLine(mSingleLineTitle); 642 } 643 } else { 644 titleView.setVisibility(View.GONE); 645 } 646 } 647 648 final TextView summaryView = (TextView) view.findViewById( 649 com.android.internal.R.id.summary); 650 if (summaryView != null) { 651 final CharSequence summary = getSummary(); 652 if (!TextUtils.isEmpty(summary)) { 653 summaryView.setText(summary); 654 summaryView.setVisibility(View.VISIBLE); 655 } else { 656 summaryView.setVisibility(View.GONE); 657 } 658 } 659 660 final ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon); 661 if (imageView != null) { 662 if (mIconResId != 0 || mIcon != null) { 663 if (mIcon == null) { 664 mIcon = getContext().getDrawable(mIconResId); 665 } 666 if (mIcon != null) { 667 imageView.setImageDrawable(mIcon); 668 } 669 } 670 if (mIcon != null) { 671 imageView.setVisibility(View.VISIBLE); 672 } else { 673 imageView.setVisibility(mIconSpaceReserved ? View.INVISIBLE : View.GONE); 674 } 675 } 676 677 final View imageFrame = view.findViewById(com.android.internal.R.id.icon_frame); 678 if (imageFrame != null) { 679 if (mIcon != null) { 680 imageFrame.setVisibility(View.VISIBLE); 681 } else { 682 imageFrame.setVisibility(mIconSpaceReserved ? View.INVISIBLE : View.GONE); 683 } 684 } 685 686 if (mShouldDisableView) { 687 setEnabledStateOnViews(view, isEnabled()); 688 } 689 } 690 691 /** 692 * Makes sure the view (and any children) get the enabled state changed. 693 */ setEnabledStateOnViews(View v, boolean enabled)694 private void setEnabledStateOnViews(View v, boolean enabled) { 695 v.setEnabled(enabled); 696 697 if (v instanceof ViewGroup) { 698 final ViewGroup vg = (ViewGroup) v; 699 for (int i = vg.getChildCount() - 1; i >= 0; i--) { 700 setEnabledStateOnViews(vg.getChildAt(i), enabled); 701 } 702 } 703 } 704 705 /** 706 * Sets the order of this Preference with respect to other Preference objects on the same level. 707 * If this is not specified, the default behavior is to sort alphabetically. The 708 * {@link PreferenceGroup#setOrderingAsAdded(boolean)} can be used to order Preference objects 709 * based on the order they appear in the XML. 710 * 711 * @param order the order for this Preference. A lower value will be shown first. Use 712 * {@link #DEFAULT_ORDER} to sort alphabetically or allow ordering from XML 713 * @see PreferenceGroup#setOrderingAsAdded(boolean) 714 * @see #DEFAULT_ORDER 715 */ setOrder(int order)716 public void setOrder(int order) { 717 if (order != mOrder) { 718 mOrder = order; 719 720 // Reorder the list 721 notifyHierarchyChanged(); 722 } 723 } 724 725 /** 726 * Gets the order of this Preference with respect to other Preference objects on the same level. 727 * 728 * @return the order of this Preference 729 * @see #setOrder(int) 730 */ getOrder()731 public int getOrder() { 732 return mOrder; 733 } 734 735 /** 736 * Sets the title for this Preference with a CharSequence. This title will be placed into the ID 737 * {@link android.R.id#title} within the View created by {@link #onCreateView(ViewGroup)}. 738 * 739 * @param title the title for this Preference 740 */ setTitle(CharSequence title)741 public void setTitle(CharSequence title) { 742 if (title == null && mTitle != null || title != null && !title.equals(mTitle)) { 743 mTitleRes = 0; 744 mTitle = title; 745 notifyChanged(); 746 } 747 } 748 749 /** 750 * Sets the title for this Preference with a resource ID. 751 * 752 * @see #setTitle(CharSequence) 753 * @param titleResId the title as a resource ID 754 */ setTitle(@tringRes int titleResId)755 public void setTitle(@StringRes int titleResId) { 756 setTitle(mContext.getString(titleResId)); 757 mTitleRes = titleResId; 758 } 759 760 /** 761 * Returns the title resource ID of this Preference. If the title did not come from a resource, 762 * {@code 0} is returned. 763 * 764 * @return the title resource 765 * @see #setTitle(int) 766 */ 767 @StringRes getTitleRes()768 public int getTitleRes() { 769 return mTitleRes; 770 } 771 772 /** 773 * Returns the title of this Preference. 774 * 775 * @return the title 776 * @see #setTitle(CharSequence) 777 */ getTitle()778 public CharSequence getTitle() { 779 return mTitle; 780 } 781 782 /** 783 * Sets the icon for this Preference with a Drawable. This icon will be placed into the ID 784 * {@link android.R.id#icon} within the View created by {@link #onCreateView(ViewGroup)}. 785 * 786 * @param icon the optional icon for this Preference 787 */ setIcon(Drawable icon)788 public void setIcon(Drawable icon) { 789 if ((icon == null && mIcon != null) || (icon != null && mIcon != icon)) { 790 mIcon = icon; 791 792 notifyChanged(); 793 } 794 } 795 796 /** 797 * Sets the icon for this Preference with a resource ID. 798 * 799 * @see #setIcon(Drawable) 800 * @param iconResId the icon as a resource ID 801 */ setIcon(@rawableRes int iconResId)802 public void setIcon(@DrawableRes int iconResId) { 803 if (mIconResId != iconResId) { 804 mIconResId = iconResId; 805 setIcon(mContext.getDrawable(iconResId)); 806 } 807 } 808 809 /** 810 * Returns the icon of this Preference. 811 * 812 * @return the icon 813 * @see #setIcon(Drawable) 814 */ getIcon()815 public Drawable getIcon() { 816 if (mIcon == null && mIconResId != 0) { 817 mIcon = getContext().getDrawable(mIconResId); 818 } 819 return mIcon; 820 } 821 822 /** 823 * Returns the summary of this Preference. 824 * 825 * @return the summary 826 * @see #setSummary(CharSequence) 827 */ getSummary()828 public CharSequence getSummary() { 829 return mSummary; 830 } 831 832 /** 833 * Sets the summary for this Preference with a CharSequence. 834 * 835 * @param summary the summary for the preference 836 */ setSummary(CharSequence summary)837 public void setSummary(CharSequence summary) { 838 if (summary == null && mSummary != null || summary != null && !summary.equals(mSummary)) { 839 mSummary = summary; 840 notifyChanged(); 841 } 842 } 843 844 /** 845 * Sets the summary for this Preference with a resource ID. 846 * 847 * @see #setSummary(CharSequence) 848 * @param summaryResId the summary as a resource 849 */ setSummary(@tringRes int summaryResId)850 public void setSummary(@StringRes int summaryResId) { 851 setSummary(mContext.getString(summaryResId)); 852 } 853 854 /** 855 * Sets whether this Preference is enabled. If disabled, it will 856 * not handle clicks. 857 * 858 * @param enabled set {@code true} to enable it 859 */ setEnabled(boolean enabled)860 public void setEnabled(boolean enabled) { 861 if (mEnabled != enabled) { 862 mEnabled = enabled; 863 864 // Enabled state can change dependent preferences' states, so notify 865 notifyDependencyChange(shouldDisableDependents()); 866 867 notifyChanged(); 868 } 869 } 870 871 /** 872 * Checks whether this Preference should be enabled in the list. 873 * 874 * @return {@code true} if this Preference is enabled, false otherwise 875 */ isEnabled()876 public boolean isEnabled() { 877 return mEnabled && mDependencyMet && mParentDependencyMet; 878 } 879 880 /** 881 * Sets whether this Preference is selectable. 882 * 883 * @param selectable set {@code true} to make it selectable 884 */ setSelectable(boolean selectable)885 public void setSelectable(boolean selectable) { 886 if (mSelectable != selectable) { 887 mSelectable = selectable; 888 notifyChanged(); 889 } 890 } 891 892 /** 893 * Checks whether this Preference should be selectable in the list. 894 * 895 * @return {@code true} if it is selectable, {@code false} otherwise 896 */ isSelectable()897 public boolean isSelectable() { 898 return mSelectable; 899 } 900 901 /** 902 * Sets whether this Preference should disable its view when it gets disabled. 903 * 904 * <p>For example, set this and {@link #setEnabled(boolean)} to false for preferences that are 905 * only displaying information and 1) should not be clickable 2) should not have the view set to 906 * the disabled state. 907 * 908 * @param shouldDisableView set {@code true} if this preference should disable its view when 909 * the preference is disabled 910 */ setShouldDisableView(boolean shouldDisableView)911 public void setShouldDisableView(boolean shouldDisableView) { 912 mShouldDisableView = shouldDisableView; 913 notifyChanged(); 914 } 915 916 /** 917 * Checks whether this Preference should disable its view when it's action is disabled. 918 * 919 * @see #setShouldDisableView(boolean) 920 * @return {@code true} if it should disable the view 921 */ getShouldDisableView()922 public boolean getShouldDisableView() { 923 return mShouldDisableView; 924 } 925 926 /** 927 * Sets whether this Preference has enabled to have its view recycled when used in the list 928 * view. By default the recycling is enabled. 929 * 930 * <p>The value can be changed only before this preference is added to the preference hierarchy. 931 * 932 * <p>If view recycling is not allowed then each time the list view populates this preference 933 * the {@link #getView(View, ViewGroup)} method receives a {@code null} convert view and needs 934 * to recreate the view. Otherwise view gets recycled and only {@link #onBindView(View)} gets 935 * called. 936 * 937 * @param enabled set {@code true} if this preference view should be recycled 938 */ 939 @CallSuper setRecycleEnabled(boolean enabled)940 public void setRecycleEnabled(boolean enabled) { 941 mRecycleEnabled = enabled; 942 notifyChanged(); 943 } 944 945 /** 946 * Checks whether this Preference has enabled to have its view recycled when used in the list 947 * view. 948 * 949 * @see #setRecycleEnabled(boolean) 950 * @return {@code true} if this preference view should be recycled 951 */ isRecycleEnabled()952 public boolean isRecycleEnabled() { 953 return mRecycleEnabled; 954 } 955 956 /** 957 * Sets whether to constrain the title of this Preference to a single line instead of 958 * letting it wrap onto multiple lines. 959 * 960 * @param singleLineTitle set {@code true} if the title should be constrained to one line 961 */ setSingleLineTitle(boolean singleLineTitle)962 public void setSingleLineTitle(boolean singleLineTitle) { 963 mHasSingleLineTitleAttr = true; 964 mSingleLineTitle = singleLineTitle; 965 notifyChanged(); 966 } 967 968 /** 969 * Gets whether the title of this preference is constrained to a single line. 970 * 971 * @see #setSingleLineTitle(boolean) 972 * @return {@code true} if the title of this preference is constrained to a single line 973 */ isSingleLineTitle()974 public boolean isSingleLineTitle() { 975 return mSingleLineTitle; 976 } 977 978 /** 979 * Sets whether to reserve the space of this Preference icon view when no icon is provided. 980 * 981 * @param iconSpaceReserved set {@code true} if the space for the icon view should be reserved 982 */ setIconSpaceReserved(boolean iconSpaceReserved)983 public void setIconSpaceReserved(boolean iconSpaceReserved) { 984 mIconSpaceReserved = iconSpaceReserved; 985 notifyChanged(); 986 } 987 988 /** 989 * Gets whether the space this preference icon view is reserved. 990 * 991 * @see #setIconSpaceReserved(boolean) 992 * @return {@code true} if the space of this preference icon view is reserved 993 */ isIconSpaceReserved()994 public boolean isIconSpaceReserved() { 995 return mIconSpaceReserved; 996 } 997 /** 998 * Returns a unique ID for this Preference. This ID should be unique across all 999 * Preference objects in a hierarchy. 1000 * 1001 * @return A unique ID for this Preference. 1002 */ 1003 @UnsupportedAppUsage getId()1004 long getId() { 1005 return mId; 1006 } 1007 1008 /** 1009 * Processes a click on the preference. This includes saving the value to 1010 * the {@link SharedPreferences}. However, the overridden method should 1011 * call {@link #callChangeListener(Object)} to make sure the client wants to 1012 * update the preference's state with the new value. 1013 */ onClick()1014 protected void onClick() { 1015 } 1016 1017 /** 1018 * Sets the key for this Preference, which is used as a key to the {@link SharedPreferences} or 1019 * {@link PreferenceDataStore}. This should be unique for the package. 1020 * 1021 * @param key The key for the preference. 1022 */ setKey(String key)1023 public void setKey(String key) { 1024 mKey = key; 1025 1026 if (mRequiresKey && !hasKey()) { 1027 requireKey(); 1028 } 1029 } 1030 1031 /** 1032 * Gets the key for this Preference, which is also the key used for storing values into 1033 * {@link SharedPreferences} or {@link PreferenceDataStore}. 1034 * 1035 * @return The key. 1036 */ getKey()1037 public String getKey() { 1038 return mKey; 1039 } 1040 1041 /** 1042 * Checks whether the key is present, and if it isn't throws an 1043 * exception. This should be called by subclasses that persist their preferences. 1044 * 1045 * @throws IllegalStateException If there is no key assigned. 1046 */ requireKey()1047 void requireKey() { 1048 if (mKey == null) { 1049 throw new IllegalStateException("Preference does not have a key assigned."); 1050 } 1051 1052 mRequiresKey = true; 1053 } 1054 1055 /** 1056 * Checks whether this Preference has a valid key. 1057 * 1058 * @return True if the key exists and is not a blank string, false otherwise. 1059 */ hasKey()1060 public boolean hasKey() { 1061 return !TextUtils.isEmpty(mKey); 1062 } 1063 1064 /** 1065 * Checks whether this Preference is persistent. If it is, it stores its value(s) into 1066 * the persistent {@link SharedPreferences} storage by default or into 1067 * {@link PreferenceDataStore} if assigned. 1068 * 1069 * @return True if it is persistent. 1070 */ isPersistent()1071 public boolean isPersistent() { 1072 return mPersistent; 1073 } 1074 1075 /** 1076 * Checks whether, at the given time this method is called, this Preference should store/restore 1077 * its value(s) into the {@link SharedPreferences} or into {@link PreferenceDataStore} if 1078 * assigned. This, at minimum, checks whether this Preference is persistent and it currently has 1079 * a key. Before you save/restore from the storage, check this first. 1080 * 1081 * @return True if it should persist the value. 1082 */ shouldPersist()1083 protected boolean shouldPersist() { 1084 return mPreferenceManager != null && isPersistent() && hasKey(); 1085 } 1086 1087 /** 1088 * Sets whether this Preference is persistent. When persistent, it stores its value(s) into 1089 * the persistent {@link SharedPreferences} storage by default or into 1090 * {@link PreferenceDataStore} if assigned. 1091 * 1092 * @param persistent set {@code true} if it should store its value(s) into the storage. 1093 */ setPersistent(boolean persistent)1094 public void setPersistent(boolean persistent) { 1095 mPersistent = persistent; 1096 } 1097 1098 /** 1099 * Call this method after the user changes the preference, but before the 1100 * internal state is set. This allows the client to ignore the user value. 1101 * 1102 * @param newValue The new value of this Preference. 1103 * @return True if the user value should be set as the preference 1104 * value (and persisted). 1105 */ callChangeListener(Object newValue)1106 protected boolean callChangeListener(Object newValue) { 1107 return mOnChangeListener == null || mOnChangeListener.onPreferenceChange(this, newValue); 1108 } 1109 1110 /** 1111 * Sets the callback to be invoked when this Preference is changed by the 1112 * user (but before the internal state has been updated). 1113 * 1114 * @param onPreferenceChangeListener The callback to be invoked. 1115 */ setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener)1116 public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) { 1117 mOnChangeListener = onPreferenceChangeListener; 1118 } 1119 1120 /** 1121 * Returns the callback to be invoked when this Preference is changed by the 1122 * user (but before the internal state has been updated). 1123 * 1124 * @return The callback to be invoked. 1125 */ getOnPreferenceChangeListener()1126 public OnPreferenceChangeListener getOnPreferenceChangeListener() { 1127 return mOnChangeListener; 1128 } 1129 1130 /** 1131 * Sets the callback to be invoked when this Preference is clicked. 1132 * 1133 * @param onPreferenceClickListener The callback to be invoked. 1134 */ setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener)1135 public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) { 1136 mOnClickListener = onPreferenceClickListener; 1137 } 1138 1139 /** 1140 * Returns the callback to be invoked when this Preference is clicked. 1141 * 1142 * @return The callback to be invoked. 1143 */ getOnPreferenceClickListener()1144 public OnPreferenceClickListener getOnPreferenceClickListener() { 1145 return mOnClickListener; 1146 } 1147 1148 /** 1149 * Called when a click should be performed. 1150 * 1151 * @param preferenceScreen A {@link PreferenceScreen} whose hierarchy click 1152 * listener should be called in the proper order (between other 1153 * processing). May be {@code null}. 1154 * @hide 1155 */ 1156 @UnsupportedAppUsage performClick(PreferenceScreen preferenceScreen)1157 public void performClick(PreferenceScreen preferenceScreen) { 1158 1159 if (!isEnabled()) { 1160 return; 1161 } 1162 1163 onClick(); 1164 1165 if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) { 1166 return; 1167 } 1168 1169 PreferenceManager preferenceManager = getPreferenceManager(); 1170 if (preferenceManager != null) { 1171 PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager 1172 .getOnPreferenceTreeClickListener(); 1173 if (preferenceScreen != null && listener != null 1174 && listener.onPreferenceTreeClick(preferenceScreen, this)) { 1175 return; 1176 } 1177 } 1178 1179 if (mIntent != null) { 1180 Context context = getContext(); 1181 context.startActivity(mIntent); 1182 } 1183 } 1184 1185 /** 1186 * Allows a Preference to intercept key events without having focus. 1187 * For example, SeekBarPreference uses this to intercept +/- to adjust 1188 * the progress. 1189 * @return True if the Preference handled the key. Returns false by default. 1190 * @hide 1191 */ 1192 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) onKey(View v, int keyCode, KeyEvent event)1193 public boolean onKey(View v, int keyCode, KeyEvent event) { 1194 return false; 1195 } 1196 1197 /** 1198 * Returns the {@link android.content.Context} of this Preference. 1199 * Each Preference in a Preference hierarchy can be 1200 * from different Context (for example, if multiple activities provide preferences into a single 1201 * {@link PreferenceActivity}). This Context will be used to save the Preference values. 1202 * 1203 * @return The Context of this Preference. 1204 */ getContext()1205 public Context getContext() { 1206 return mContext; 1207 } 1208 1209 /** 1210 * Returns the {@link SharedPreferences} where this Preference can read its 1211 * value(s). Usually, it's easier to use one of the helper read methods: 1212 * {@link #getPersistedBoolean(boolean)}, {@link #getPersistedFloat(float)}, 1213 * {@link #getPersistedInt(int)}, {@link #getPersistedLong(long)}, 1214 * {@link #getPersistedString(String)}. To save values, see 1215 * {@link #getEditor()}. 1216 * <p> 1217 * In some cases, writes to the {@link #getEditor()} will not be committed 1218 * right away and hence not show up in the returned 1219 * {@link SharedPreferences}, this is intended behavior to improve 1220 * performance. 1221 * 1222 * @return the {@link SharedPreferences} where this Preference reads its value(s). If 1223 * this preference isn't attached to a Preference hierarchy or if 1224 * a {@link PreferenceDataStore} has been set, this method returns {@code null}. 1225 * @see #getEditor() 1226 * @see #setPreferenceDataStore(PreferenceDataStore) 1227 */ getSharedPreferences()1228 public SharedPreferences getSharedPreferences() { 1229 if (mPreferenceManager == null || getPreferenceDataStore() != null) { 1230 return null; 1231 } 1232 1233 return mPreferenceManager.getSharedPreferences(); 1234 } 1235 1236 /** 1237 * Returns an {@link SharedPreferences.Editor} where this Preference can 1238 * save its value(s). Usually it's easier to use one of the helper save 1239 * methods: {@link #persistBoolean(boolean)}, {@link #persistFloat(float)}, 1240 * {@link #persistInt(int)}, {@link #persistLong(long)}, 1241 * {@link #persistString(String)}. To read values, see 1242 * {@link #getSharedPreferences()}. If {@link #shouldCommit()} returns 1243 * true, it is this Preference's responsibility to commit. 1244 * <p> 1245 * In some cases, writes to this will not be committed right away and hence 1246 * not show up in the SharedPreferences, this is intended behavior to 1247 * improve performance. 1248 * 1249 * @return a {@link SharedPreferences.Editor} where this preference saves its value(s). If 1250 * this preference isn't attached to a Preference hierarchy or if 1251 * a {@link PreferenceDataStore} has been set, this method returns {@code null}. 1252 * @see #shouldCommit() 1253 * @see #getSharedPreferences() 1254 * @see #setPreferenceDataStore(PreferenceDataStore) 1255 */ getEditor()1256 public SharedPreferences.Editor getEditor() { 1257 if (mPreferenceManager == null || getPreferenceDataStore() != null) { 1258 return null; 1259 } 1260 1261 return mPreferenceManager.getEditor(); 1262 } 1263 1264 /** 1265 * Returns whether the {@link Preference} should commit its saved value(s) in 1266 * {@link #getEditor()}. This may return false in situations where batch 1267 * committing is being done (by the manager) to improve performance. 1268 * 1269 * <p>If this preference is using {@link PreferenceDataStore} this value is irrelevant. 1270 * 1271 * @return Whether the Preference should commit its saved value(s). 1272 * @see #getEditor() 1273 */ shouldCommit()1274 public boolean shouldCommit() { 1275 if (mPreferenceManager == null) { 1276 return false; 1277 } 1278 1279 return mPreferenceManager.shouldCommit(); 1280 } 1281 1282 /** 1283 * Compares Preference objects based on order (if set), otherwise alphabetically on the titles. 1284 * 1285 * @param another The Preference to compare to this one. 1286 * @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another</var>; 1287 * greater than 0 if this Preference sorts after <var>another</var>. 1288 */ 1289 @Override compareTo(Preference another)1290 public int compareTo(Preference another) { 1291 if (mOrder != another.mOrder) { 1292 // Do order comparison 1293 return mOrder - another.mOrder; 1294 } else if (mTitle == another.mTitle) { 1295 // If titles are null or share same object comparison 1296 return 0; 1297 } else if (mTitle == null) { 1298 return 1; 1299 } else if (another.mTitle == null) { 1300 return -1; 1301 } else { 1302 // Do name comparison 1303 return CharSequences.compareToIgnoreCase(mTitle, another.mTitle); 1304 } 1305 } 1306 1307 /** 1308 * Sets the internal change listener. 1309 * 1310 * @param listener The listener. 1311 * @see #notifyChanged() 1312 */ 1313 @UnsupportedAppUsage setOnPreferenceChangeInternalListener(OnPreferenceChangeInternalListener listener)1314 final void setOnPreferenceChangeInternalListener(OnPreferenceChangeInternalListener listener) { 1315 mListener = listener; 1316 } 1317 1318 /** 1319 * Should be called when the data of this {@link Preference} has changed. 1320 */ notifyChanged()1321 protected void notifyChanged() { 1322 if (mListener != null) { 1323 mListener.onPreferenceChange(this); 1324 } 1325 } 1326 1327 /** 1328 * Should be called when a Preference has been 1329 * added/removed from this group, or the ordering should be 1330 * re-evaluated. 1331 */ notifyHierarchyChanged()1332 protected void notifyHierarchyChanged() { 1333 if (mListener != null) { 1334 mListener.onPreferenceHierarchyChange(this); 1335 } 1336 } 1337 1338 /** 1339 * Gets the {@link PreferenceManager} that manages this Preference object's tree. 1340 * 1341 * @return The {@link PreferenceManager}. 1342 */ getPreferenceManager()1343 public PreferenceManager getPreferenceManager() { 1344 return mPreferenceManager; 1345 } 1346 1347 /** 1348 * Called when this Preference has been attached to a Preference hierarchy. 1349 * Make sure to call the super implementation. 1350 * 1351 * @param preferenceManager The PreferenceManager of the hierarchy. 1352 */ onAttachedToHierarchy(PreferenceManager preferenceManager)1353 protected void onAttachedToHierarchy(PreferenceManager preferenceManager) { 1354 mPreferenceManager = preferenceManager; 1355 1356 mId = preferenceManager.getNextId(); 1357 1358 dispatchSetInitialValue(); 1359 } 1360 1361 /** 1362 * Called when the Preference hierarchy has been attached to the 1363 * {@link PreferenceActivity}. This can also be called when this 1364 * Preference has been attached to a group that was already attached 1365 * to the {@link PreferenceActivity}. 1366 */ onAttachedToActivity()1367 protected void onAttachedToActivity() { 1368 // At this point, the hierarchy that this preference is in is connected 1369 // with all other preferences. 1370 registerDependency(); 1371 } 1372 1373 /** 1374 * Assigns a {@link PreferenceGroup} as the parent of this Preference. Set {@code null} to 1375 * remove the current parent. 1376 * 1377 * @param parentGroup Parent preference group of this Preference or {@code null} if none. 1378 */ assignParent(@ullable PreferenceGroup parentGroup)1379 void assignParent(@Nullable PreferenceGroup parentGroup) { 1380 mParentGroup = parentGroup; 1381 } 1382 registerDependency()1383 private void registerDependency() { 1384 1385 if (TextUtils.isEmpty(mDependencyKey)) return; 1386 1387 Preference preference = findPreferenceInHierarchy(mDependencyKey); 1388 if (preference != null) { 1389 preference.registerDependent(this); 1390 } else { 1391 throw new IllegalStateException("Dependency \"" + mDependencyKey 1392 + "\" not found for preference \"" + mKey + "\" (title: \"" + mTitle + "\""); 1393 } 1394 } 1395 unregisterDependency()1396 private void unregisterDependency() { 1397 if (mDependencyKey != null) { 1398 final Preference oldDependency = findPreferenceInHierarchy(mDependencyKey); 1399 if (oldDependency != null) { 1400 oldDependency.unregisterDependent(this); 1401 } 1402 } 1403 } 1404 1405 /** 1406 * Finds a Preference in this hierarchy (the whole thing, 1407 * even above/below your {@link PreferenceScreen} screen break) with the given 1408 * key. 1409 * <p> 1410 * This only functions after we have been attached to a hierarchy. 1411 * 1412 * @param key The key of the Preference to find. 1413 * @return The Preference that uses the given key. 1414 */ findPreferenceInHierarchy(String key)1415 protected Preference findPreferenceInHierarchy(String key) { 1416 if (TextUtils.isEmpty(key) || mPreferenceManager == null) { 1417 return null; 1418 } 1419 1420 return mPreferenceManager.findPreference(key); 1421 } 1422 1423 /** 1424 * Adds a dependent Preference on this Preference so we can notify it. 1425 * Usually, the dependent Preference registers itself (it's good for it to 1426 * know it depends on something), so please use 1427 * {@link Preference#setDependency(String)} on the dependent Preference. 1428 * 1429 * @param dependent The dependent Preference that will be enabled/disabled 1430 * according to the state of this Preference. 1431 */ 1432 @UnsupportedAppUsage registerDependent(Preference dependent)1433 private void registerDependent(Preference dependent) { 1434 if (mDependents == null) { 1435 mDependents = new ArrayList<Preference>(); 1436 } 1437 1438 mDependents.add(dependent); 1439 1440 dependent.onDependencyChanged(this, shouldDisableDependents()); 1441 } 1442 1443 /** 1444 * Removes a dependent Preference on this Preference. 1445 * 1446 * @param dependent The dependent Preference that will be enabled/disabled 1447 * according to the state of this Preference. 1448 * @return Returns the same Preference object, for chaining multiple calls 1449 * into a single statement. 1450 */ unregisterDependent(Preference dependent)1451 private void unregisterDependent(Preference dependent) { 1452 if (mDependents != null) { 1453 mDependents.remove(dependent); 1454 } 1455 } 1456 1457 /** 1458 * Notifies any listening dependents of a change that affects the 1459 * dependency. 1460 * 1461 * @param disableDependents Whether this Preference should disable 1462 * its dependents. 1463 */ notifyDependencyChange(boolean disableDependents)1464 public void notifyDependencyChange(boolean disableDependents) { 1465 final List<Preference> dependents = mDependents; 1466 1467 if (dependents == null) { 1468 return; 1469 } 1470 1471 final int dependentsCount = dependents.size(); 1472 for (int i = 0; i < dependentsCount; i++) { 1473 dependents.get(i).onDependencyChanged(this, disableDependents); 1474 } 1475 } 1476 1477 /** 1478 * Called when the dependency changes. 1479 * 1480 * @param dependency The Preference that this Preference depends on. 1481 * @param disableDependent Set true to disable this Preference. 1482 */ onDependencyChanged(Preference dependency, boolean disableDependent)1483 public void onDependencyChanged(Preference dependency, boolean disableDependent) { 1484 if (mDependencyMet == disableDependent) { 1485 mDependencyMet = !disableDependent; 1486 1487 // Enabled state can change dependent preferences' states, so notify 1488 notifyDependencyChange(shouldDisableDependents()); 1489 1490 notifyChanged(); 1491 } 1492 } 1493 1494 /** 1495 * Called when the implicit parent dependency changes. 1496 * 1497 * @param parent The Preference that this Preference depends on. 1498 * @param disableChild Set true to disable this Preference. 1499 */ onParentChanged(Preference parent, boolean disableChild)1500 public void onParentChanged(Preference parent, boolean disableChild) { 1501 if (mParentDependencyMet == disableChild) { 1502 mParentDependencyMet = !disableChild; 1503 1504 // Enabled state can change dependent preferences' states, so notify 1505 notifyDependencyChange(shouldDisableDependents()); 1506 1507 notifyChanged(); 1508 } 1509 } 1510 1511 /** 1512 * Checks whether this preference's dependents should currently be 1513 * disabled. 1514 * 1515 * @return True if the dependents should be disabled, otherwise false. 1516 */ shouldDisableDependents()1517 public boolean shouldDisableDependents() { 1518 return !isEnabled(); 1519 } 1520 1521 /** 1522 * Sets the key of a Preference that this Preference will depend on. If that 1523 * Preference is not set or is off, this Preference will be disabled. 1524 * 1525 * @param dependencyKey The key of the Preference that this depends on. 1526 */ setDependency(String dependencyKey)1527 public void setDependency(String dependencyKey) { 1528 // Unregister the old dependency, if we had one 1529 unregisterDependency(); 1530 1531 // Register the new 1532 mDependencyKey = dependencyKey; 1533 registerDependency(); 1534 } 1535 1536 /** 1537 * Returns the key of the dependency on this Preference. 1538 * 1539 * @return The key of the dependency. 1540 * @see #setDependency(String) 1541 */ getDependency()1542 public String getDependency() { 1543 return mDependencyKey; 1544 } 1545 1546 /** 1547 * Returns the {@link PreferenceGroup} which is this Preference assigned to or {@code null} if 1548 * this preference is not assigned to any group or is a root Preference. 1549 * 1550 * @return the parent PreferenceGroup or {@code null} if not attached to any 1551 */ 1552 @Nullable getParent()1553 public PreferenceGroup getParent() { 1554 return mParentGroup; 1555 } 1556 1557 /** 1558 * Called when this Preference is being removed from the hierarchy. You 1559 * should remove any references to this Preference that you know about. Make 1560 * sure to call through to the superclass implementation. 1561 */ 1562 @CallSuper onPrepareForRemoval()1563 protected void onPrepareForRemoval() { 1564 unregisterDependency(); 1565 } 1566 1567 /** 1568 * Sets the default value for this Preference, which will be set either if 1569 * persistence is off or persistence is on and the preference is not found 1570 * in the persistent storage. 1571 * 1572 * @param defaultValue The default value. 1573 */ setDefaultValue(Object defaultValue)1574 public void setDefaultValue(Object defaultValue) { 1575 mDefaultValue = defaultValue; 1576 } 1577 dispatchSetInitialValue()1578 private void dispatchSetInitialValue() { 1579 if (getPreferenceDataStore() != null) { 1580 onSetInitialValue(true, mDefaultValue); 1581 return; 1582 } 1583 1584 // By now, we know if we are persistent. 1585 final boolean shouldPersist = shouldPersist(); 1586 if (!shouldPersist || !getSharedPreferences().contains(mKey)) { 1587 if (mDefaultValue != null) { 1588 onSetInitialValue(false, mDefaultValue); 1589 } 1590 } else { 1591 onSetInitialValue(true, null); 1592 } 1593 } 1594 1595 /** 1596 * Implement this to set the initial value of the Preference. 1597 * 1598 * <p>If <var>restorePersistedValue</var> is true, you should restore the 1599 * Preference value from the {@link android.content.SharedPreferences}. If 1600 * <var>restorePersistedValue</var> is false, you should set the Preference 1601 * value to defaultValue that is given (and possibly store to SharedPreferences 1602 * if {@link #shouldPersist()} is true). 1603 * 1604 * <p>In case of using {@link PreferenceDataStore}, the <var>restorePersistedValue</var> is 1605 * always {@code true}. But the default value (if provided) is set. 1606 * 1607 * <p>This may not always be called. One example is if it should not persist 1608 * but there is no default value given. 1609 * 1610 * @param restorePersistedValue True to restore the persisted value; 1611 * false to use the given <var>defaultValue</var>. 1612 * @param defaultValue The default value for this Preference. Only use this 1613 * if <var>restorePersistedValue</var> is false. 1614 */ onSetInitialValue(boolean restorePersistedValue, Object defaultValue)1615 protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { 1616 } 1617 tryCommit(SharedPreferences.Editor editor)1618 private void tryCommit(SharedPreferences.Editor editor) { 1619 if (mPreferenceManager.shouldCommit()) { 1620 try { 1621 editor.apply(); 1622 } catch (AbstractMethodError unused) { 1623 // The app injected its own pre-Gingerbread 1624 // SharedPreferences.Editor implementation without 1625 // an apply method. 1626 editor.commit(); 1627 } 1628 } 1629 } 1630 1631 /** 1632 * Attempts to persist a String if this Preference is persistent. 1633 * 1634 * @param value The value to persist. 1635 * @return True if this Preference is persistent. (This is not whether the 1636 * value was persisted, since we may not necessarily commit if there 1637 * will be a batch commit later.) 1638 * @see #getPersistedString(String) 1639 */ persistString(String value)1640 protected boolean persistString(String value) { 1641 if (!shouldPersist()) { 1642 return false; 1643 } 1644 1645 // Shouldn't store null 1646 if (TextUtils.equals(value, getPersistedString(null))) { 1647 // It's already there, so the same as persisting 1648 return true; 1649 } 1650 1651 PreferenceDataStore dataStore = getPreferenceDataStore(); 1652 if (dataStore != null) { 1653 dataStore.putString(mKey, value); 1654 } else { 1655 SharedPreferences.Editor editor = mPreferenceManager.getEditor(); 1656 editor.putString(mKey, value); 1657 tryCommit(editor); 1658 } 1659 return true; 1660 } 1661 1662 /** 1663 * Attempts to get a persisted String if this Preference is persistent. 1664 * 1665 * @param defaultReturnValue The default value to return if either this 1666 * Preference is not persistent or this Preference is not present. 1667 * @return The value from the data store or the default return 1668 * value. 1669 * @see #persistString(String) 1670 */ getPersistedString(String defaultReturnValue)1671 protected String getPersistedString(String defaultReturnValue) { 1672 if (!shouldPersist()) { 1673 return defaultReturnValue; 1674 } 1675 1676 PreferenceDataStore dataStore = getPreferenceDataStore(); 1677 if (dataStore != null) { 1678 return dataStore.getString(mKey, defaultReturnValue); 1679 } 1680 1681 return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue); 1682 } 1683 1684 /** 1685 * Attempts to persist a set of Strings if this Preference is persistent. 1686 * 1687 * @param values The values to persist. 1688 * @return True if this Preference is persistent. (This is not whether the 1689 * value was persisted, since we may not necessarily commit if there 1690 * will be a batch commit later.) 1691 * @see #getPersistedStringSet(Set) 1692 */ persistStringSet(Set<String> values)1693 public boolean persistStringSet(Set<String> values) { 1694 if (!shouldPersist()) { 1695 return false; 1696 } 1697 1698 // Shouldn't store null 1699 if (values.equals(getPersistedStringSet(null))) { 1700 // It's already there, so the same as persisting 1701 return true; 1702 } 1703 1704 PreferenceDataStore dataStore = getPreferenceDataStore(); 1705 if (dataStore != null) { 1706 dataStore.putStringSet(mKey, values); 1707 } else { 1708 SharedPreferences.Editor editor = mPreferenceManager.getEditor(); 1709 editor.putStringSet(mKey, values); 1710 tryCommit(editor); 1711 } 1712 return true; 1713 } 1714 1715 /** 1716 * Attempts to get a persisted set of Strings if this Preference is persistent. 1717 * 1718 * @param defaultReturnValue The default value to return if either this 1719 * Preference is not persistent or this Preference is not present. 1720 * @return The value from the data store or the default return 1721 * value. 1722 * @see #persistStringSet(Set) 1723 */ getPersistedStringSet(Set<String> defaultReturnValue)1724 public Set<String> getPersistedStringSet(Set<String> defaultReturnValue) { 1725 if (!shouldPersist()) { 1726 return defaultReturnValue; 1727 } 1728 1729 PreferenceDataStore dataStore = getPreferenceDataStore(); 1730 if (dataStore != null) { 1731 return dataStore.getStringSet(mKey, defaultReturnValue); 1732 } 1733 1734 return mPreferenceManager.getSharedPreferences().getStringSet(mKey, defaultReturnValue); 1735 } 1736 1737 /** 1738 * Attempts to persist an int if this Preference is persistent. 1739 * 1740 * @param value The value to persist. 1741 * @return True if this Preference is persistent. (This is not whether the 1742 * value was persisted, since we may not necessarily commit if there 1743 * will be a batch commit later.) 1744 * @see #persistString(String) 1745 * @see #getPersistedInt(int) 1746 */ persistInt(int value)1747 protected boolean persistInt(int value) { 1748 if (!shouldPersist()) { 1749 return false; 1750 } 1751 1752 if (value == getPersistedInt(~value)) { 1753 // It's already there, so the same as persisting 1754 return true; 1755 } 1756 1757 PreferenceDataStore dataStore = getPreferenceDataStore(); 1758 if (dataStore != null) { 1759 dataStore.putInt(mKey, value); 1760 } else { 1761 SharedPreferences.Editor editor = mPreferenceManager.getEditor(); 1762 editor.putInt(mKey, value); 1763 tryCommit(editor); 1764 } 1765 return true; 1766 } 1767 1768 /** 1769 * Attempts to get a persisted int if this Preference is persistent. 1770 * 1771 * @param defaultReturnValue The default value to return if either this 1772 * Preference is not persistent or this Preference is not present. 1773 * @return The value from the data store or the default return 1774 * value. 1775 * @see #getPersistedString(String) 1776 * @see #persistInt(int) 1777 */ getPersistedInt(int defaultReturnValue)1778 protected int getPersistedInt(int defaultReturnValue) { 1779 if (!shouldPersist()) { 1780 return defaultReturnValue; 1781 } 1782 1783 PreferenceDataStore dataStore = getPreferenceDataStore(); 1784 if (dataStore != null) { 1785 return dataStore.getInt(mKey, defaultReturnValue); 1786 } 1787 1788 return mPreferenceManager.getSharedPreferences().getInt(mKey, defaultReturnValue); 1789 } 1790 1791 /** 1792 * Attempts to persist a long if this Preference is persistent. 1793 * 1794 * @param value The value to persist. 1795 * @return True if this Preference is persistent. (This is not whether the 1796 * value was persisted, since we may not necessarily commit if there 1797 * will be a batch commit later.) 1798 * @see #persistString(String) 1799 * @see #getPersistedFloat(float) 1800 */ persistFloat(float value)1801 protected boolean persistFloat(float value) { 1802 if (!shouldPersist()) { 1803 return false; 1804 } 1805 1806 if (value == getPersistedFloat(Float.NaN)) { 1807 // It's already there, so the same as persisting 1808 return true; 1809 } 1810 1811 PreferenceDataStore dataStore = getPreferenceDataStore(); 1812 if (dataStore != null) { 1813 dataStore.putFloat(mKey, value); 1814 } else { 1815 SharedPreferences.Editor editor = mPreferenceManager.getEditor(); 1816 editor.putFloat(mKey, value); 1817 tryCommit(editor); 1818 } 1819 return true; 1820 } 1821 1822 /** 1823 * Attempts to get a persisted float if this Preference is persistent. 1824 * 1825 * @param defaultReturnValue The default value to return if either this 1826 * Preference is not persistent or this Preference is not present. 1827 * @return The value from the data store or the default return 1828 * value. 1829 * @see #getPersistedString(String) 1830 * @see #persistFloat(float) 1831 */ getPersistedFloat(float defaultReturnValue)1832 protected float getPersistedFloat(float defaultReturnValue) { 1833 if (!shouldPersist()) { 1834 return defaultReturnValue; 1835 } 1836 1837 PreferenceDataStore dataStore = getPreferenceDataStore(); 1838 if (dataStore != null) { 1839 return dataStore.getFloat(mKey, defaultReturnValue); 1840 } 1841 1842 return mPreferenceManager.getSharedPreferences().getFloat(mKey, defaultReturnValue); 1843 } 1844 1845 /** 1846 * Attempts to persist a long if this Preference is persistent. 1847 * 1848 * @param value The value to persist. 1849 * @return True if this Preference is persistent. (This is not whether the 1850 * value was persisted, since we may not necessarily commit if there 1851 * will be a batch commit later.) 1852 * @see #persistString(String) 1853 * @see #getPersistedLong(long) 1854 */ persistLong(long value)1855 protected boolean persistLong(long value) { 1856 if (!shouldPersist()) { 1857 return false; 1858 } 1859 1860 if (value == getPersistedLong(~value)) { 1861 // It's already there, so the same as persisting 1862 return true; 1863 } 1864 1865 PreferenceDataStore dataStore = getPreferenceDataStore(); 1866 if (dataStore != null) { 1867 dataStore.putLong(mKey, value); 1868 } else { 1869 SharedPreferences.Editor editor = mPreferenceManager.getEditor(); 1870 editor.putLong(mKey, value); 1871 tryCommit(editor); 1872 } 1873 return true; 1874 } 1875 1876 /** 1877 * Attempts to get a persisted long if this Preference is persistent. 1878 * 1879 * @param defaultReturnValue The default value to return if either this 1880 * Preference is not persistent or this Preference is not present. 1881 * @return The value from the data store or the default return 1882 * value. 1883 * @see #getPersistedString(String) 1884 * @see #persistLong(long) 1885 */ getPersistedLong(long defaultReturnValue)1886 protected long getPersistedLong(long defaultReturnValue) { 1887 if (!shouldPersist()) { 1888 return defaultReturnValue; 1889 } 1890 1891 PreferenceDataStore dataStore = getPreferenceDataStore(); 1892 if (dataStore != null) { 1893 return dataStore.getLong(mKey, defaultReturnValue); 1894 } 1895 1896 return mPreferenceManager.getSharedPreferences().getLong(mKey, defaultReturnValue); 1897 } 1898 1899 /** 1900 * Attempts to persist a boolean if this Preference is persistent. 1901 * 1902 * @param value The value to persist. 1903 * @return True if this Preference is persistent. (This is not whether the 1904 * value was persisted, since we may not necessarily commit if there 1905 * will be a batch commit later.) 1906 * @see #persistString(String) 1907 * @see #getPersistedBoolean(boolean) 1908 */ persistBoolean(boolean value)1909 protected boolean persistBoolean(boolean value) { 1910 if (!shouldPersist()) { 1911 return false; 1912 } 1913 1914 if (value == getPersistedBoolean(!value)) { 1915 // It's already there, so the same as persisting 1916 return true; 1917 } 1918 1919 PreferenceDataStore dataStore = getPreferenceDataStore(); 1920 if (dataStore != null) { 1921 dataStore.putBoolean(mKey, value); 1922 } else { 1923 SharedPreferences.Editor editor = mPreferenceManager.getEditor(); 1924 editor.putBoolean(mKey, value); 1925 tryCommit(editor); 1926 } 1927 return true; 1928 } 1929 1930 /** 1931 * Attempts to get a persisted boolean if this Preference is persistent. 1932 * 1933 * @param defaultReturnValue The default value to return if either this 1934 * Preference is not persistent or this Preference is not present. 1935 * @return The value from the data store or the default return 1936 * value. 1937 * @see #getPersistedString(String) 1938 * @see #persistBoolean(boolean) 1939 */ getPersistedBoolean(boolean defaultReturnValue)1940 protected boolean getPersistedBoolean(boolean defaultReturnValue) { 1941 if (!shouldPersist()) { 1942 return defaultReturnValue; 1943 } 1944 1945 PreferenceDataStore dataStore = getPreferenceDataStore(); 1946 if (dataStore != null) { 1947 return dataStore.getBoolean(mKey, defaultReturnValue); 1948 } 1949 1950 return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue); 1951 } 1952 1953 @Override toString()1954 public String toString() { 1955 return getFilterableStringBuilder().toString(); 1956 } 1957 1958 /** 1959 * Returns the text that will be used to filter this Preference depending on 1960 * user input. 1961 * <p> 1962 * If overridding and calling through to the superclass, make sure to prepend 1963 * your additions with a space. 1964 * 1965 * @return Text as a {@link StringBuilder} that will be used to filter this 1966 * preference. By default, this is the title and summary 1967 * (concatenated with a space). 1968 */ getFilterableStringBuilder()1969 StringBuilder getFilterableStringBuilder() { 1970 StringBuilder sb = new StringBuilder(); 1971 CharSequence title = getTitle(); 1972 if (!TextUtils.isEmpty(title)) { 1973 sb.append(title).append(' '); 1974 } 1975 CharSequence summary = getSummary(); 1976 if (!TextUtils.isEmpty(summary)) { 1977 sb.append(summary).append(' '); 1978 } 1979 if (sb.length() > 0) { 1980 // Drop the last space 1981 sb.setLength(sb.length() - 1); 1982 } 1983 return sb; 1984 } 1985 1986 /** 1987 * Store this Preference hierarchy's frozen state into the given container. 1988 * 1989 * @param container The Bundle in which to save the instance of this Preference. 1990 * 1991 * @see #restoreHierarchyState 1992 * @see #onSaveInstanceState 1993 */ saveHierarchyState(Bundle container)1994 public void saveHierarchyState(Bundle container) { 1995 dispatchSaveInstanceState(container); 1996 } 1997 1998 /** 1999 * Called by {@link #saveHierarchyState} to store the instance for this Preference and its 2000 * children. May be overridden to modify how the save happens for children. For example, some 2001 * Preference objects may want to not store an instance for their children. 2002 * 2003 * @param container The Bundle in which to save the instance of this Preference. 2004 * 2005 * @see #saveHierarchyState 2006 * @see #onSaveInstanceState 2007 */ dispatchSaveInstanceState(Bundle container)2008 void dispatchSaveInstanceState(Bundle container) { 2009 if (hasKey()) { 2010 mBaseMethodCalled = false; 2011 Parcelable state = onSaveInstanceState(); 2012 if (!mBaseMethodCalled) { 2013 throw new IllegalStateException( 2014 "Derived class did not call super.onSaveInstanceState()"); 2015 } 2016 if (state != null) { 2017 container.putParcelable(mKey, state); 2018 } 2019 } 2020 } 2021 2022 /** 2023 * Hook allowing a Preference to generate a representation of its internal 2024 * state that can later be used to create a new instance with that same 2025 * state. This state should only contain information that is not persistent 2026 * or can be reconstructed later. 2027 * 2028 * @return A Parcelable object containing the current dynamic state of this Preference, or 2029 * {@code null} if there is nothing interesting to save. The default implementation 2030 * returns {@code null}. 2031 * @see #onRestoreInstanceState 2032 * @see #saveHierarchyState 2033 */ onSaveInstanceState()2034 protected Parcelable onSaveInstanceState() { 2035 mBaseMethodCalled = true; 2036 return BaseSavedState.EMPTY_STATE; 2037 } 2038 2039 /** 2040 * Restore this Preference hierarchy's previously saved state from the given container. 2041 * 2042 * @param container The Bundle that holds the previously saved state. 2043 * 2044 * @see #saveHierarchyState 2045 * @see #onRestoreInstanceState 2046 */ restoreHierarchyState(Bundle container)2047 public void restoreHierarchyState(Bundle container) { 2048 dispatchRestoreInstanceState(container); 2049 } 2050 2051 /** 2052 * Called by {@link #restoreHierarchyState} to retrieve the saved state for this 2053 * Preference and its children. May be overridden to modify how restoring 2054 * happens to the children of a Preference. For example, some Preference objects may 2055 * not want to save state for their children. 2056 * 2057 * @param container The Bundle that holds the previously saved state. 2058 * @see #restoreHierarchyState 2059 * @see #onRestoreInstanceState 2060 */ dispatchRestoreInstanceState(Bundle container)2061 void dispatchRestoreInstanceState(Bundle container) { 2062 if (hasKey()) { 2063 Parcelable state = container.getParcelable(mKey); 2064 if (state != null) { 2065 mBaseMethodCalled = false; 2066 onRestoreInstanceState(state); 2067 if (!mBaseMethodCalled) { 2068 throw new IllegalStateException( 2069 "Derived class did not call super.onRestoreInstanceState()"); 2070 } 2071 } 2072 } 2073 } 2074 2075 /** 2076 * Hook allowing a Preference to re-apply a representation of its internal state that had 2077 * previously been generated by {@link #onSaveInstanceState}. This function will never be called 2078 * with a {@code null} state. 2079 * 2080 * @param state The saved state that had previously been returned by 2081 * {@link #onSaveInstanceState}. 2082 * @see #onSaveInstanceState 2083 * @see #restoreHierarchyState 2084 */ onRestoreInstanceState(Parcelable state)2085 protected void onRestoreInstanceState(Parcelable state) { 2086 mBaseMethodCalled = true; 2087 if (state != BaseSavedState.EMPTY_STATE && state != null) { 2088 throw new IllegalArgumentException("Wrong state class -- expecting Preference State"); 2089 } 2090 } 2091 2092 /** 2093 * A base class for managing the instance state of a {@link Preference}. 2094 * 2095 * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> 2096 * <a href="{@docRoot}reference/androidx/preference/package-summary.html"> 2097 * Preference Library</a> for consistent behavior across all devices. 2098 * For more information on using the AndroidX Preference Library see 2099 * <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>. 2100 */ 2101 @Deprecated 2102 public static class BaseSavedState extends AbsSavedState { BaseSavedState(Parcel source)2103 public BaseSavedState(Parcel source) { 2104 super(source); 2105 } 2106 BaseSavedState(Parcelable superState)2107 public BaseSavedState(Parcelable superState) { 2108 super(superState); 2109 } 2110 2111 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR = 2112 new Parcelable.Creator<BaseSavedState>() { 2113 public BaseSavedState createFromParcel(Parcel in) { 2114 return new BaseSavedState(in); 2115 } 2116 2117 public BaseSavedState[] newArray(int size) { 2118 return new BaseSavedState[size]; 2119 } 2120 }; 2121 } 2122 2123 } 2124