alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Android example source code file (Preference.java)

This example Android source code file (Preference.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Android by Example" TM.

Java - Android tags/keywords

android, basesavedstate, charsequence, content, context, default_order, illegalstateexception, object, onpreferencechangelistener, onpreferenceclicklistener, os, parcelable, preference, preferencemanager, string, textview, ui, util, view, viewgroup

The Preference.java Android example source code

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.preference;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import com.android.internal.util.CharSequences;
import android.view.AbsSavedState;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;

/**
 * Represents the basic Preference UI building
 * block displayed by a {@link PreferenceActivity} in the form of a
 * {@link ListView}. This class provides the {@link View} to be displayed in
 * the activity and associates with a {@link SharedPreferences} to
 * store/retrieve the preference data.
 * <p>
 * When specifying a preference hierarchy in XML, each element can point to a
 * subclass of {@link Preference}, similar to the view hierarchy and layouts.
 * <p>
 * This class contains a {@code key} that will be used as the key into the
 * {@link SharedPreferences}. It is up to the subclass to decide how to store
 * the value.
 * 
 * @attr ref android.R.styleable#Preference_key
 * @attr ref android.R.styleable#Preference_title
 * @attr ref android.R.styleable#Preference_summary
 * @attr ref android.R.styleable#Preference_order
 * @attr ref android.R.styleable#Preference_layout
 * @attr ref android.R.styleable#Preference_widgetLayout
 * @attr ref android.R.styleable#Preference_enabled
 * @attr ref android.R.styleable#Preference_selectable
 * @attr ref android.R.styleable#Preference_dependency
 * @attr ref android.R.styleable#Preference_persistent
 * @attr ref android.R.styleable#Preference_defaultValue
 * @attr ref android.R.styleable#Preference_shouldDisableView
 */
public class Preference implements Comparable<Preference>, OnDependencyChangeListener { 
    /**
     * Specify for {@link #setOrder(int)} if a specific order is not required.
     */
    public static final int DEFAULT_ORDER = Integer.MAX_VALUE;

    private Context mContext;
    private PreferenceManager mPreferenceManager;
    
    /**
     * Set when added to hierarchy since we need a unique ID within that
     * hierarchy.
     */
    private long mId;
    
    private OnPreferenceChangeListener mOnChangeListener;
    private OnPreferenceClickListener mOnClickListener;

    private int mOrder = DEFAULT_ORDER;
    private CharSequence mTitle;
    private CharSequence mSummary;
    private String mKey;
    private Intent mIntent;
    private boolean mEnabled = true;
    private boolean mSelectable = true;
    private boolean mRequiresKey;
    private boolean mPersistent = true;
    private String mDependencyKey;
    private Object mDefaultValue;
    private boolean mDependencyMet = true;
    
    /**
     * @see #setShouldDisableView(boolean)
     */
    private boolean mShouldDisableView = true;
    
    private int mLayoutResId = com.android.internal.R.layout.preference;
    private int mWidgetLayoutResId;
    private boolean mHasSpecifiedLayout = false;
    
    private OnPreferenceChangeInternalListener mListener;
    
    private List<Preference> mDependents;
    
    private boolean mBaseMethodCalled;
    
    /**
     * Interface definition for a callback to be invoked when the value of this
     * {@link Preference} has been changed by the user and is
     * about to be set and/or persisted.  This gives the client a chance
     * to prevent setting and/or persisting the value.
     */
    public interface OnPreferenceChangeListener {
        /**
         * Called when a Preference has been changed by the user. This is
         * called before the state of the Preference is about to be updated and
         * before the state is persisted.
         * 
         * @param preference The changed Preference.
         * @param newValue The new value of the Preference.
         * @return True to update the state of the Preference with the new value.
         */
        boolean onPreferenceChange(Preference preference, Object newValue);
    }

    /**
     * Interface definition for a callback to be invoked when a {@link Preference} is
     * clicked.
     */
    public interface OnPreferenceClickListener {
        /**
         * Called when a Preference has been clicked.
         *
         * @param preference The Preference that was clicked.
         * @return True if the click was handled.
         */
        boolean onPreferenceClick(Preference preference);
    }

    /**
     * Interface definition for a callback to be invoked when this
     * {@link Preference} is changed or, if this is a group, there is an
     * addition/removal of {@link Preference}(s). This is used internally.
     */
    interface OnPreferenceChangeInternalListener {
        /**
         * Called when this Preference has changed.
         * 
         * @param preference This preference.
         */
        void onPreferenceChange(Preference preference);
        
        /**
         * Called when this group has added/removed {@link Preference}(s).
         * 
         * @param preference This Preference.
         */
        void onPreferenceHierarchyChange(Preference preference);
    }

    /**
     * Perform inflation from XML and apply a class-specific base style. This
     * constructor of Preference allows subclasses to use their own base
     * style when they are inflating. For example, a {@link CheckBoxPreference}
     * constructor calls this version of the super class constructor and
     * supplies {@code android.R.attr.checkBoxPreferenceStyle} for <var>defStyle.
     * This allows the theme's checkbox preference style to modify all of the base
     * preference attributes as well as the {@link CheckBoxPreference} class's
     * attributes.
     * 
     * @param context The Context this is associated with, through which it can
     *            access the current theme, resources, {@link SharedPreferences},
     *            etc.
     * @param attrs The attributes of the XML tag that is inflating the preference.
     * @param defStyle The default style to apply to this preference. If 0, no style
     *            will be applied (beyond what is included in the theme). This
     *            may either be an attribute resource, whose value will be
     *            retrieved from the current theme, or an explicit style
     *            resource.
     * @see #Preference(Context, AttributeSet)
     */
    public Preference(Context context, AttributeSet attrs, int defStyle) {
        mContext = context;

        TypedArray a = context.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.Preference, defStyle, 0);
        for (int i = a.getIndexCount(); i >= 0; i--) {
            int attr = a.getIndex(i); 
            switch (attr) {
                case com.android.internal.R.styleable.Preference_key:
                    mKey = a.getString(attr);
                    break;
                    
                case com.android.internal.R.styleable.Preference_title:
                    mTitle = a.getString(attr);
                    break;
                    
                case com.android.internal.R.styleable.Preference_summary:
                    mSummary = a.getString(attr);
                    break;
                    
                case com.android.internal.R.styleable.Preference_order:
                    mOrder = a.getInt(attr, mOrder);
                    break;

                case com.android.internal.R.styleable.Preference_layout:
                    mLayoutResId = a.getResourceId(attr, mLayoutResId);
                    break;

                case com.android.internal.R.styleable.Preference_widgetLayout:
                    mWidgetLayoutResId = a.getResourceId(attr, mWidgetLayoutResId);
                    break;
                    
                case com.android.internal.R.styleable.Preference_enabled:
                    mEnabled = a.getBoolean(attr, true);
                    break;
                    
                case com.android.internal.R.styleable.Preference_selectable:
                    mSelectable = a.getBoolean(attr, true);
                    break;
                    
                case com.android.internal.R.styleable.Preference_persistent:
                    mPersistent = a.getBoolean(attr, mPersistent);
                    break;
                    
                case com.android.internal.R.styleable.Preference_dependency:
                    mDependencyKey = a.getString(attr);
                    break;
                    
                case com.android.internal.R.styleable.Preference_defaultValue:
                    mDefaultValue = onGetDefaultValue(a, attr);
                    break;
                    
                case com.android.internal.R.styleable.Preference_shouldDisableView:
                    mShouldDisableView = a.getBoolean(attr, mShouldDisableView);
                    break;
            }
        }
        a.recycle();

        if (!getClass().getName().startsWith("android.preference")) {
            // For subclasses not in this package, assume the worst and don't cache views
            mHasSpecifiedLayout = true;
        }
    }
    
    /**
     * Constructor that is called when inflating a Preference from XML. This is
     * called when a Preference is being constructed from an XML file, supplying
     * attributes that were specified in the XML file. This version uses a
     * default style of 0, so the only attribute values applied are those in the
     * Context's Theme and the given AttributeSet.
     * 
     * @param context The Context this is associated with, through which it can
     *            access the current theme, resources, {@link SharedPreferences},
     *            etc.
     * @param attrs The attributes of the XML tag that is inflating the
     *            preference.
     * @see #Preference(Context, AttributeSet, int)
     */
    public Preference(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * Constructor to create a Preference.
     * 
     * @param context The Context in which to store Preference values.
     */
    public Preference(Context context) {
        this(context, null);
    }

    /**
     * Called when a Preference is being inflated and the default value
     * attribute needs to be read. Since different Preference types have
     * different value types, the subclass should get and return the default
     * value which will be its value type.
     * <p>
     * For example, if the value type is String, the body of the method would
     * proxy to {@link TypedArray#getString(int)}.
     * 
     * @param a The set of attributes.
     * @param index The index of the default value attribute.
     * @return The default value of this preference type.
     */
    protected Object onGetDefaultValue(TypedArray a, int index) {
        return null;
    }
    
    /**
     * Sets an {@link Intent} to be used for
     * {@link Context#startActivity(Intent)} when this Preference is clicked.
     * 
     * @param intent The intent associated with this Preference.
     */
    public void setIntent(Intent intent) {
        mIntent = intent;
    }
    
    /**
     * Return the {@link Intent} associated with this Preference.
     * 
     * @return The {@link Intent} last set via {@link #setIntent(Intent)} or XML. 
     */
    public Intent getIntent() {
        return mIntent;
    }

    /**
     * Sets the layout resource that is inflated as the {@link View} to be shown
     * for this Preference. In most cases, the default layout is sufficient for
     * custom Preference objects and only the widget layout needs to be changed.
     * <p>
     * This layout should contain a {@link ViewGroup} with ID
     * {@link android.R.id#widget_frame} to be the parent of the specific widget
     * for this Preference. It should similarly contain
     * {@link android.R.id#title} and {@link android.R.id#summary}.
     * 
     * @param layoutResId The layout resource ID to be inflated and returned as
     *            a {@link View}.
     * @see #setWidgetLayoutResource(int)
     */
    public void setLayoutResource(int layoutResId) {
        if (layoutResId != mLayoutResId) {
            // Layout changed
            mHasSpecifiedLayout = true;
        }

        mLayoutResId = layoutResId;
    }
    
    /**
     * Gets the layout resource that will be shown as the {@link View} for this Preference.
     * 
     * @return The layout resource ID.
     */
    public int getLayoutResource() {
        return mLayoutResId;
    }
    
    /**
     * Sets The layout for the controllable widget portion of this Preference. This
     * is inflated into the main layout. For example, a {@link CheckBoxPreference}
     * would specify a custom layout (consisting of just the CheckBox) here,
     * instead of creating its own main layout.
     * 
     * @param widgetLayoutResId The layout resource ID to be inflated into the
     *            main layout.
     * @see #setLayoutResource(int)
     */
    public void setWidgetLayoutResource(int widgetLayoutResId) {
        if (widgetLayoutResId != mWidgetLayoutResId) {
            // Layout changed
            mHasSpecifiedLayout = true;
        }
        mWidgetLayoutResId = widgetLayoutResId;
    }

    /**
     * Gets the layout resource for the controllable widget portion of this Preference.
     * 
     * @return The layout resource ID.
     */
    public int getWidgetLayoutResource() {
        return mWidgetLayoutResId;
    }
    
    /**
     * Gets the View that will be shown in the {@link PreferenceActivity}.
     * 
     * @param convertView The old View to reuse, if possible. Note: You should
     *            check that this View is non-null and of an appropriate type
     *            before using. If it is not possible to convert this View to
     *            display the correct data, this method can create a new View.
     * @param parent The parent that this View will eventually be attached to.
     * @return Returns the same Preference object, for chaining multiple calls
     *         into a single statement.
     * @see #onCreateView(ViewGroup)
     * @see #onBindView(View)
     */
    public View getView(View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = onCreateView(parent);
        }
        onBindView(convertView);
        return convertView;
    }
    
    /**
     * Creates the View to be shown for this Preference in the
     * {@link PreferenceActivity}. The default behavior is to inflate the main
     * layout of this Preference (see {@link #setLayoutResource(int)}. If
     * changing this behavior, please specify a {@link ViewGroup} with ID
     * {@link android.R.id#widget_frame}.
     * <p>
     * Make sure to call through to the superclass's implementation.
     * 
     * @param parent The parent that this View will eventually be attached to.
     * @return The View that displays this Preference.
     * @see #onBindView(View)
     */
    protected View onCreateView(ViewGroup parent) {
        final LayoutInflater layoutInflater =
            (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        
        final View layout = layoutInflater.inflate(mLayoutResId, parent, false); 
        
        if (mWidgetLayoutResId != 0) {
            final ViewGroup widgetFrame = (ViewGroup)layout.findViewById(com.android.internal.R.id.widget_frame);
            layoutInflater.inflate(mWidgetLayoutResId, widgetFrame);
        }

        return layout;
    }
    
    /**
     * Binds the created View to the data for this Preference.
     * <p>
     * This is a good place to grab references to custom Views in the layout and
     * set properties on them.
     * <p>
     * Make sure to call through to the superclass's implementation.
     * 
     * @param view The View that shows this Preference.
     * @see #onCreateView(ViewGroup)
     */
    protected void onBindView(View view) {
        TextView textView = (TextView) view.findViewById(com.android.internal.R.id.title); 
        if (textView != null) {
            textView.setText(getTitle());
        }
        
        textView = (TextView) view.findViewById(com.android.internal.R.id.summary);
        if (textView != null) {
            final CharSequence summary = getSummary();
            if (!TextUtils.isEmpty(summary)) {
                if (textView.getVisibility() != View.VISIBLE) {
                    textView.setVisibility(View.VISIBLE);
                }
                
                textView.setText(getSummary());
            } else {
                if (textView.getVisibility() != View.GONE) {
                    textView.setVisibility(View.GONE);
                }
            }
        }
        
        if (mShouldDisableView) {
            setEnabledStateOnViews(view, isEnabled());
        }
    }
    
    /**
     * Makes sure the view (and any children) get the enabled state changed.
     */
    private void setEnabledStateOnViews(View v, boolean enabled) {
        v.setEnabled(enabled);
        
        if (v instanceof ViewGroup) {
            final ViewGroup vg = (ViewGroup) v;
            for (int i = vg.getChildCount() - 1; i >= 0; i--) {
                setEnabledStateOnViews(vg.getChildAt(i), enabled);
            }
        }
    }
    
    /**
     * Sets the order of this Preference with respect to other
     * Preference objects on the same level. If this is not specified, the
     * default behavior is to sort alphabetically. The
     * {@link PreferenceGroup#setOrderingAsAdded(boolean)} can be used to order
     * Preference objects based on the order they appear in the XML.
     * 
     * @param order The order for this Preference. A lower value will be shown
     *            first. Use {@link #DEFAULT_ORDER} to sort alphabetically or
     *            allow ordering from XML.
     * @see PreferenceGroup#setOrderingAsAdded(boolean)
     * @see #DEFAULT_ORDER
     */
    public void setOrder(int order) {
        if (order != mOrder) {
            mOrder = order;

            // Reorder the list 
            notifyHierarchyChanged();
        }
    }
    
    /**
     * Gets the order of this Preference with respect to other Preference objects
     * on the same level.
     * 
     * @return The order of this Preference.
     * @see #setOrder(int)
     */
    public int getOrder() {
        return mOrder;
    }

    /**
     * Sets the title for this Preference with a CharSequence. 
     * This title will be placed into the ID
     * {@link android.R.id#title} within the View created by
     * {@link #onCreateView(ViewGroup)}.
     * 
     * @param title The title for this Preference.
     */
    public void setTitle(CharSequence title) {
        if (title == null && mTitle != null || title != null && !title.equals(mTitle)) {
            mTitle = title;
            notifyChanged();
        }
    }
    
    /**
     * Sets the title for this Preference with a resource ID. 
     * 
     * @see #setTitle(CharSequence)
     * @param titleResId The title as a resource ID.
     */
    public void setTitle(int titleResId) {
        setTitle(mContext.getString(titleResId));
    }
    
    /**
     * Returns the title of this Preference.
     * 
     * @return The title.
     * @see #setTitle(CharSequence)
     */
    public CharSequence getTitle() {
        return mTitle;
    }

    /**
     * Returns the summary of this Preference.
     * 
     * @return The summary.
     * @see #setSummary(CharSequence)
     */
    public CharSequence getSummary() {
        return mSummary;
    }

    /**
     * Sets the summary for this Preference with a CharSequence. 
     * 
     * @param summary The summary for the preference.
     */
    public void setSummary(CharSequence summary) {
        if (summary == null && mSummary != null || summary != null && !summary.equals(mSummary)) {
            mSummary = summary;
            notifyChanged();
        }
    }

    /**
     * Sets the summary for this Preference with a resource ID. 
     * 
     * @see #setSummary(CharSequence)
     * @param summaryResId The summary as a resource.
     */
    public void setSummary(int summaryResId) {
        setSummary(mContext.getString(summaryResId));
    }
    
    /**
     * Sets whether this Preference is enabled. If disabled, it will
     * not handle clicks.
     * 
     * @param enabled Set true to enable it.
     */
    public void setEnabled(boolean enabled) {
        if (mEnabled != enabled) {
            mEnabled = enabled;

            // Enabled state can change dependent preferences' states, so notify
            notifyDependencyChange(shouldDisableDependents());

            notifyChanged();
        }
    }
    
    /**
     * Checks whether this Preference should be enabled in the list.
     * 
     * @return True if this Preference is enabled, false otherwise.
     */
    public boolean isEnabled() {
        return mEnabled && mDependencyMet;
    }

    /**
     * Sets whether this Preference is selectable.
     * 
     * @param selectable Set true to make it selectable.
     */
    public void setSelectable(boolean selectable) {
        if (mSelectable != selectable) {
            mSelectable = selectable;
            notifyChanged();
        }
    }
    
    /**
     * Checks whether this Preference should be selectable in the list.
     * 
     * @return True if it is selectable, false otherwise.
     */
    public boolean isSelectable() {
        return mSelectable;
    }

    /**
     * Sets whether this Preference should disable its view when it gets
     * disabled.
     * <p>
     * For example, set this and {@link #setEnabled(boolean)} to false for
     * preferences that are only displaying information and 1) should not be
     * clickable 2) should not have the view set to the disabled state.
     * 
     * @param shouldDisableView Set true if this preference should disable its view
     *            when the preference is disabled.
     */
    public void setShouldDisableView(boolean shouldDisableView) {
        mShouldDisableView = shouldDisableView;
        notifyChanged();
    }
    
    /**
     * Checks whether this Preference should disable its view when it's action is disabled.
     * @see #setShouldDisableView(boolean)
     * @return True if it should disable the view. 
     */
    public boolean getShouldDisableView() {
        return mShouldDisableView;
    }

    /**
     * Returns a unique ID for this Preference.  This ID should be unique across all
     * Preference objects in a hierarchy.
     * 
     * @return A unique ID for this Preference.
     */
    long getId() {
        return mId;
    }
    
    /**
     * Processes a click on the preference. This includes saving the value to
     * the {@link SharedPreferences}. However, the overridden method should
     * call {@link #callChangeListener(Object)} to make sure the client wants to
     * update the preference's state with the new value.
     */
    protected void onClick() {
    }
    
    /**
     * Sets the key for this Preference, which is used as a key to the
     * {@link SharedPreferences}. This should be unique for the package.
     * 
     * @param key The key for the preference.
     */
    public void setKey(String key) {
        mKey = key;
        
        if (mRequiresKey && !hasKey()) {
            requireKey();
        }
    }
    
    /**
     * Gets the key for this Preference, which is also the key used for storing
     * values into SharedPreferences.
     * 
     * @return The key.
     */
    public String getKey() {
        return mKey;
    }
    
    /**
     * Checks whether the key is present, and if it isn't throws an
     * exception. This should be called by subclasses that store preferences in
     * the {@link SharedPreferences}.
     * 
     * @throws IllegalStateException If there is no key assigned.
     */
    void requireKey() {
        if (mKey == null) {
            throw new IllegalStateException("Preference does not have a key assigned.");
        }
        
        mRequiresKey = true;
    }
    
    /**
     * Checks whether this Preference has a valid key.
     * 
     * @return True if the key exists and is not a blank string, false otherwise.
     */
    public boolean hasKey() {
        return !TextUtils.isEmpty(mKey);
    }
    
    /**
     * Checks whether this Preference is persistent. If it is, it stores its value(s) into
     * the persistent {@link SharedPreferences} storage.
     * 
     * @return True if it is persistent.
     */
    public boolean isPersistent() {
        return mPersistent;
    }
    
    /**
     * Checks whether, at the given time this method is called,
     * this Preference should store/restore its value(s) into the
     * {@link SharedPreferences}. This, at minimum, checks whether this
     * Preference is persistent and it currently has a key. Before you
     * save/restore from the {@link SharedPreferences}, check this first.
     * 
     * @return True if it should persist the value.
     */
    protected boolean shouldPersist() {
        return mPreferenceManager != null && isPersistent() && hasKey();
    }
    
    /**
     * Sets whether this Preference is persistent. When persistent,
     * it stores its value(s) into the persistent {@link SharedPreferences}
     * storage.
     * 
     * @param persistent Set true if it should store its value(s) into the {@link SharedPreferences}.
     */
    public void setPersistent(boolean persistent) {
        mPersistent = persistent;
    }
    
    /**
     * Call this method after the user changes the preference, but before the
     * internal state is set. This allows the client to ignore the user value.
     * 
     * @param newValue The new value of this Preference.
     * @return True if the user value should be set as the preference
     *         value (and persisted).
     */
    protected boolean callChangeListener(Object newValue) {
        return mOnChangeListener == null ? true : mOnChangeListener.onPreferenceChange(this, newValue);
    }
    
    /**
     * Sets the callback to be invoked when this Preference is changed by the
     * user (but before the internal state has been updated).
     * 
     * @param onPreferenceChangeListener The callback to be invoked.
     */
    public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) {
        mOnChangeListener = onPreferenceChangeListener;
    }

    /**
     * Returns the callback to be invoked when this Preference is changed by the
     * user (but before the internal state has been updated).
     * 
     * @return The callback to be invoked.
     */
    public OnPreferenceChangeListener getOnPreferenceChangeListener() {
        return mOnChangeListener;
    }

    /**
     * Sets the callback to be invoked when this Preference is clicked.
     * 
     * @param onPreferenceClickListener The callback to be invoked.
     */
    public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
        mOnClickListener = onPreferenceClickListener;
    }

    /**
     * Returns the callback to be invoked when this Preference is clicked.
     * 
     * @return The callback to be invoked.
     */
    public OnPreferenceClickListener getOnPreferenceClickListener() {
        return mOnClickListener;
    }

    /**
     * Called when a click should be performed.
     * 
     * @param preferenceScreen A {@link PreferenceScreen} whose hierarchy click
     *            listener should be called in the proper order (between other
     *            processing). May be null.
     */
    void performClick(PreferenceScreen preferenceScreen) {
        
        if (!isEnabled()) {
            return;
        }
        
        onClick();
        
        if (mOnClickListener != null && mOnClickListener.onPreferenceClick(this)) {
            return;
        }
        
        PreferenceManager preferenceManager = getPreferenceManager();
        if (preferenceManager != null) {
            PreferenceManager.OnPreferenceTreeClickListener listener = preferenceManager
                    .getOnPreferenceTreeClickListener();
            if (preferenceScreen != null && listener != null
                    && listener.onPreferenceTreeClick(preferenceScreen, this)) {
                return;
            }
        }
        
        if (mIntent != null) {
            Context context = getContext();
            context.startActivity(mIntent);
        }
    }
    
    /**
     * Returns the {@link android.content.Context} of this Preference. 
     * Each Preference in a Preference hierarchy can be
     * from different Context (for example, if multiple activities provide preferences into a single
     * {@link PreferenceActivity}). This Context will be used to save the Preference values.
     * 
     * @return The Context of this Preference.
     */
    public Context getContext() {
        return mContext;
    }
    
    /**
     * Returns the {@link SharedPreferences} where this Preference can read its
     * value(s). Usually, it's easier to use one of the helper read methods:
     * {@link #getPersistedBoolean(boolean)}, {@link #getPersistedFloat(float)},
     * {@link #getPersistedInt(int)}, {@link #getPersistedLong(long)},
     * {@link #getPersistedString(String)}. To save values, see
     * {@link #getEditor()}.
     * <p>
     * In some cases, writes to the {@link #getEditor()} will not be committed
     * right away and hence not show up in the returned
     * {@link SharedPreferences}, this is intended behavior to improve
     * performance.
     * 
     * @return The {@link SharedPreferences} where this Preference reads its
     *         value(s), or null if it isn't attached to a Preference hierarchy.
     * @see #getEditor()
     */
    public SharedPreferences getSharedPreferences() {
        if (mPreferenceManager == null) {
            return null;
        }
        
        return mPreferenceManager.getSharedPreferences();
    }
    
    /**
     * Returns an {@link SharedPreferences.Editor} where this Preference can
     * save its value(s). Usually it's easier to use one of the helper save
     * methods: {@link #persistBoolean(boolean)}, {@link #persistFloat(float)},
     * {@link #persistInt(int)}, {@link #persistLong(long)},
     * {@link #persistString(String)}. To read values, see
     * {@link #getSharedPreferences()}. If {@link #shouldCommit()} returns
     * true, it is this Preference's responsibility to commit.
     * <p>
     * In some cases, writes to this will not be committed right away and hence
     * not show up in the SharedPreferences, this is intended behavior to
     * improve performance.
     * 
     * @return A {@link SharedPreferences.Editor} where this preference saves
     *         its value(s), or null if it isn't attached to a Preference
     *         hierarchy.
     * @see #shouldCommit()
     * @see #getSharedPreferences()
     */
    public SharedPreferences.Editor getEditor() {
        if (mPreferenceManager == null) {
            return null;
        }
        
        return mPreferenceManager.getEditor();
    }
    
    /**
     * Returns whether the {@link Preference} should commit its saved value(s) in
     * {@link #getEditor()}. This may return false in situations where batch
     * committing is being done (by the manager) to improve performance.
     * 
     * @return Whether the Preference should commit its saved value(s).
     * @see #getEditor()
     */
    public boolean shouldCommit() {
        if (mPreferenceManager == null) {
            return false;
        }
        
        return mPreferenceManager.shouldCommit();
    }
    
    /**
     * Compares Preference objects based on order (if set), otherwise alphabetically on the titles.
     * 
     * @param another The Preference to compare to this one.
     * @return 0 if the same; less than 0 if this Preference sorts ahead of <var>another;
     *          greater than 0 if this Preference sorts after <var>another.
     */
    public int compareTo(Preference another) {
        if (mOrder != DEFAULT_ORDER
                || (mOrder == DEFAULT_ORDER && another.mOrder != DEFAULT_ORDER)) {
            // Do order comparison
            return mOrder - another.mOrder; 
        } else if (mTitle == null) {
            return 1;
        } else if (another.mTitle == null) {
            return -1;
        } else {
            // Do name comparison
            return CharSequences.compareToIgnoreCase(mTitle, another.mTitle);
        }
    }
    
    /**
     * Sets the internal change listener.
     * 
     * @param listener The listener.
     * @see #notifyChanged()
     */
    final void setOnPreferenceChangeInternalListener(OnPreferenceChangeInternalListener listener) {
        mListener = listener;
    }

    /**
     * Should be called when the data of this {@link Preference} has changed.
     */
    protected void notifyChanged() {
        if (mListener != null) {
            mListener.onPreferenceChange(this);
        }
    }
    
    /**
     * Should be called when a Preference has been
     * added/removed from this group, or the ordering should be
     * re-evaluated.
     */
    protected void notifyHierarchyChanged() {
        if (mListener != null) {
            mListener.onPreferenceHierarchyChange(this);
        }
    }

    /**
     * Gets the {@link PreferenceManager} that manages this Preference object's tree.
     * 
     * @return The {@link PreferenceManager}.
     */
    public PreferenceManager getPreferenceManager() {
        return mPreferenceManager;
    }
    
    /**
     * Called when this Preference has been attached to a Preference hierarchy.
     * Make sure to call the super implementation.
     * 
     * @param preferenceManager The PreferenceManager of the hierarchy.
     */
    protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
        mPreferenceManager = preferenceManager;
        
        mId = preferenceManager.getNextId();
        
        dispatchSetInitialValue();
    }
    
    /**
     * Called when the Preference hierarchy has been attached to the
     * {@link PreferenceActivity}. This can also be called when this
     * Preference has been attached to a group that was already attached
     * to the {@link PreferenceActivity}.
     */
    protected void onAttachedToActivity() {
        // At this point, the hierarchy that this preference is in is connected
        // with all other preferences.
        registerDependency();
    }

    private void registerDependency() {
        
        if (TextUtils.isEmpty(mDependencyKey)) return;
        
        Preference preference = findPreferenceInHierarchy(mDependencyKey);
        if (preference != null) {
            preference.registerDependent(this);
        } else {
            throw new IllegalStateException("Dependency \"" + mDependencyKey
                    + "\" not found for preference \"" + mKey + "\" (title: \"" + mTitle + "\"");
        }
    }

    private void unregisterDependency() {
        if (mDependencyKey != null) {
            final Preference oldDependency = findPreferenceInHierarchy(mDependencyKey);
            if (oldDependency != null) {
                oldDependency.unregisterDependent(this);
            }
        }
    }
    
    /**
     * Finds a Preference in this hierarchy (the whole thing,
     * even above/below your {@link PreferenceScreen} screen break) with the given
     * key.
     * <p>
     * This only functions after we have been attached to a hierarchy.
     * 
     * @param key The key of the Preference to find.
     * @return The Preference that uses the given key.
     */
    protected Preference findPreferenceInHierarchy(String key) {
        if (TextUtils.isEmpty(key) || mPreferenceManager == null) {
            return null;
        }
        
        return mPreferenceManager.findPreference(key);
    }
    
    /**
     * Adds a dependent Preference on this Preference so we can notify it.
     * Usually, the dependent Preference registers itself (it's good for it to
     * know it depends on something), so please use
     * {@link Preference#setDependency(String)} on the dependent Preference.
     * 
     * @param dependent The dependent Preference that will be enabled/disabled
     *            according to the state of this Preference.
     */
    private void registerDependent(Preference dependent) {
        if (mDependents == null) {
            mDependents = new ArrayList<Preference>();
        }
        
        mDependents.add(dependent);
        
        dependent.onDependencyChanged(this, shouldDisableDependents());
    }
    
    /**
     * Removes a dependent Preference on this Preference.
     * 
     * @param dependent The dependent Preference that will be enabled/disabled
     *            according to the state of this Preference.
     * @return Returns the same Preference object, for chaining multiple calls
     *         into a single statement.
     */
    private void unregisterDependent(Preference dependent) {
        if (mDependents != null) {
            mDependents.remove(dependent);
        }
    }
    
    /**
     * Notifies any listening dependents of a change that affects the
     * dependency.
     * 
     * @param disableDependents Whether this Preference should disable
     *            its dependents.
     */
    public void notifyDependencyChange(boolean disableDependents) {
        final List<Preference> dependents = mDependents;
        
        if (dependents == null) {
            return;
        }
        
        final int dependentsCount = dependents.size();
        for (int i = 0; i < dependentsCount; i++) {
            dependents.get(i).onDependencyChanged(this, disableDependents);
        }
    }

    /**
     * Called when the dependency changes.
     * 
     * @param dependency The Preference that this Preference depends on.
     * @param disableDependent Set true to disable this Preference.
     */
    public void onDependencyChanged(Preference dependency, boolean disableDependent) {
        if (mDependencyMet == disableDependent) {
            mDependencyMet = !disableDependent;

            // Enabled state can change dependent preferences' states, so notify
            notifyDependencyChange(shouldDisableDependents());

            notifyChanged();
        }
    }
    
    /**
     * Checks whether this preference's dependents should currently be
     * disabled.
     * 
     * @return True if the dependents should be disabled, otherwise false.
     */
    public boolean shouldDisableDependents() {
        return !isEnabled();
    }
    
    /**
     * Sets the key of a Preference that this Preference will depend on. If that
     * Preference is not set or is off, this Preference will be disabled.
     * 
     * @param dependencyKey The key of the Preference that this depends on.
     */
    public void setDependency(String dependencyKey) {
        // Unregister the old dependency, if we had one
        unregisterDependency();
        
        // Register the new
        mDependencyKey = dependencyKey;
        registerDependency();
    }
    
    /**
     * Returns the key of the dependency on this Preference.
     * 
     * @return The key of the dependency.
     * @see #setDependency(String)
     */
    public String getDependency() {
        return mDependencyKey;
    }
    
    /**
     * Called when this Preference is being removed from the hierarchy. You
     * should remove any references to this Preference that you know about. Make
     * sure to call through to the superclass implementation.
     */
    protected void onPrepareForRemoval() {
        unregisterDependency();
    }
    
    /**
     * Sets the default value for this Preference, which will be set either if
     * persistence is off or persistence is on and the preference is not found
     * in the persistent storage.
     * 
     * @param defaultValue The default value.
     */
    public void setDefaultValue(Object defaultValue) {
        mDefaultValue = defaultValue;
    }
    
    private void dispatchSetInitialValue() {
        // By now, we know if we are persistent.
        final boolean shouldPersist = shouldPersist();
        if (!shouldPersist || !getSharedPreferences().contains(mKey)) {
            if (mDefaultValue != null) {
                onSetInitialValue(false, mDefaultValue);
            }
        } else {
            onSetInitialValue(true, null);
        }
    }
    
    /**
     * Implement this to set the initial value of the Preference. 
     * <p>
     * If <var>restorePersistedValue is true, you should restore the 
     * Preference value from the {@link android.content.SharedPreferences}. If 
     * <var>restorePersistedValue is false, you should set the Preference 
     * value to defaultValue that is given (and possibly store to SharedPreferences 
     * if {@link #shouldPersist()} is true).
     * <p>
     * This may not always be called. One example is if it should not persist
     * but there is no default value given.
     * 
     * @param restorePersistedValue True to restore the persisted value;
     *            false to use the given <var>defaultValue.
     * @param defaultValue The default value for this Preference. Only use this
     *            if <var>restorePersistedValue is false.
     */
    protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
    }

    private void tryCommit(SharedPreferences.Editor editor) {
        if (mPreferenceManager.shouldCommit()) {
            editor.commit();
        }
    }
    
    /**
     * Attempts to persist a String to the {@link android.content.SharedPreferences}.
     * <p>
     * This will check if this Preference is persistent, get an editor from
     * the {@link PreferenceManager}, put in the string, and check if we should commit (and
     * commit if so).
     * 
     * @param value The value to persist.
     * @return True if the Preference is persistent. (This is not whether the
     *         value was persisted, since we may not necessarily commit if there
     *         will be a batch commit later.)
     * @see #getPersistedString(String)
     */
    protected boolean persistString(String value) {
        if (shouldPersist()) {
            // Shouldn't store null
            if (value == getPersistedString(null)) {
                // It's already there, so the same as persisting
                return true;
            }
            
            SharedPreferences.Editor editor = mPreferenceManager.getEditor();
            editor.putString(mKey, value);
            tryCommit(editor);
            return true;
        }
        return false;
    }
    
    /**
     * Attempts to get a persisted String from the {@link android.content.SharedPreferences}.
     * <p>
     * This will check if this Preference is persistent, get the SharedPreferences
     * from the {@link PreferenceManager}, and get the value.
     * 
     * @param defaultReturnValue The default value to return if either the
     *            Preference is not persistent or the Preference is not in the
     *            shared preferences.
     * @return The value from the SharedPreferences or the default return
     *         value.
     * @see #persistString(String)
     */
    protected String getPersistedString(String defaultReturnValue) {
        if (!shouldPersist()) {
            return defaultReturnValue;
        }
        
        return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue);
    }
    
    /**
     * Attempts to persist an int to the {@link android.content.SharedPreferences}.
     * 
     * @param value The value to persist.
     * @return True if the Preference is persistent. (This is not whether the
     *         value was persisted, since we may not necessarily commit if there
     *         will be a batch commit later.)
     * @see #persistString(String)
     * @see #getPersistedInt(int)
     */
    protected boolean persistInt(int value) {
        if (shouldPersist()) {
            if (value == getPersistedInt(~value)) {
                // It's already there, so the same as persisting
                return true;
            }
            
            SharedPreferences.Editor editor = mPreferenceManager.getEditor();
            editor.putInt(mKey, value);
            tryCommit(editor);
            return true;
        }
        return false;
    }
    
    /**
     * Attempts to get a persisted int from the {@link android.content.SharedPreferences}.
     * 
     * @param defaultReturnValue The default value to return if either this
     *            Preference is not persistent or this Preference is not in the
     *            SharedPreferences.
     * @return The value from the SharedPreferences or the default return
     *         value.
     * @see #getPersistedString(String)
     * @see #persistInt(int)
     */
    protected int getPersistedInt(int defaultReturnValue) {
        if (!shouldPersist()) {
            return defaultReturnValue;
        }
        
        return mPreferenceManager.getSharedPreferences().getInt(mKey, defaultReturnValue);
    }
    
    /**
     * Attempts to persist a float to the {@link android.content.SharedPreferences}.
     * 
     * @param value The value to persist.
     * @return True if this Preference is persistent. (This is not whether the
     *         value was persisted, since we may not necessarily commit if there
     *         will be a batch commit later.)
     * @see #persistString(String)
     * @see #getPersistedFloat(float)
     */
    protected boolean persistFloat(float value) {
        if (shouldPersist()) {
            if (value == getPersistedFloat(Float.NaN)) {
                // It's already there, so the same as persisting
                return true;
            }

            SharedPreferences.Editor editor = mPreferenceManager.getEditor();
            editor.putFloat(mKey, value);
            tryCommit(editor);
            return true;
        }
        return false;
    }
    
    /**
     * Attempts to get a persisted float from the {@link android.content.SharedPreferences}.
     * 
     * @param defaultReturnValue The default value to return if either this
     *            Preference is not persistent or this Preference is not in the
     *            SharedPreferences.
     * @return The value from the SharedPreferences or the default return
     *         value.
     * @see #getPersistedString(String)
     * @see #persistFloat(float)
     */
    protected float getPersistedFloat(float defaultReturnValue) {
        if (!shouldPersist()) {
            return defaultReturnValue;
        }
        
        return mPreferenceManager.getSharedPreferences().getFloat(mKey, defaultReturnValue);
    }
    
    /**
     * Attempts to persist a long to the {@link android.content.SharedPreferences}.
     * 
     * @param value The value to persist.
     * @return True if this Preference is persistent. (This is not whether the
     *         value was persisted, since we may not necessarily commit if there
     *         will be a batch commit later.)
     * @see #persistString(String)
     * @see #getPersistedLong(long)
     */
    protected boolean persistLong(long value) {
        if (shouldPersist()) {
            if (value == getPersistedLong(~value)) {
                // It's already there, so the same as persisting
                return true;
            }
            
            SharedPreferences.Editor editor = mPreferenceManager.getEditor();
            editor.putLong(mKey, value);
            tryCommit(editor);
            return true;
        }
        return false;
    }
    
    /**
     * Attempts to get a persisted long from the {@link android.content.SharedPreferences}.
     * 
     * @param defaultReturnValue The default value to return if either this
     *            Preference is not persistent or this Preference is not in the
     *            SharedPreferences.
     * @return The value from the SharedPreferences or the default return
     *         value.
     * @see #getPersistedString(String)
     * @see #persistLong(long)
     */
    protected long getPersistedLong(long defaultReturnValue) {
        if (!shouldPersist()) {
            return defaultReturnValue;
        }
        
        return mPreferenceManager.getSharedPreferences().getLong(mKey, defaultReturnValue);
    }
    
    /**
     * Attempts to persist a boolean to the {@link android.content.SharedPreferences}.
     * 
     * @param value The value to persist.
     * @return True if this Preference is persistent. (This is not whether the
     *         value was persisted, since we may not necessarily commit if there
     *         will be a batch commit later.)
     * @see #persistString(String)
     * @see #getPersistedBoolean(boolean)
     */
    protected boolean persistBoolean(boolean value) {
        if (shouldPersist()) {
            if (value == getPersistedBoolean(!value)) {
                // It's already there, so the same as persisting
                return true;
            }
            
            SharedPreferences.Editor editor = mPreferenceManager.getEditor();
            editor.putBoolean(mKey, value);
            tryCommit(editor);
            return true;
        }
        return false;
    }
    
    /**
     * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}.
     * 
     * @param defaultReturnValue The default value to return if either this
     *            Preference is not persistent or this Preference is not in the
     *            SharedPreferences.
     * @return The value from the SharedPreferences or the default return
     *         value.
     * @see #getPersistedString(String)
     * @see #persistBoolean(boolean)
     */
    protected boolean getPersistedBoolean(boolean defaultReturnValue) {
        if (!shouldPersist()) {
            return defaultReturnValue;
        }
        
        return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue);
    }
    
    boolean hasSpecifiedLayout() {
        return mHasSpecifiedLayout;
    }
    
    @Override
    public String toString() {
        return getFilterableStringBuilder().toString();
    }
        
    /**
     * Returns the text that will be used to filter this Preference depending on
     * user input.
     * <p>
     * If overridding and calling through to the superclass, make sure to prepend
     * your additions with a space.
     * 
     * @return Text as a {@link StringBuilder} that will be used to filter this
     *         preference. By default, this is the title and summary
     *         (concatenated with a space).
     */
    StringBuilder getFilterableStringBuilder() {
        StringBuilder sb = new StringBuilder();
        CharSequence title = getTitle();
        if (!TextUtils.isEmpty(title)) {
            sb.append(title).append(' ');
        }
        CharSequence summary = getSummary();
        if (!TextUtils.isEmpty(summary)) {
            sb.append(summary).append(' ');
        }
        if (sb.length() > 0) {
            // Drop the last space
            sb.setLength(sb.length() - 1);
        }
        return sb;
    }

    /**
     * Store this Preference hierarchy's frozen state into the given container.
     * 
     * @param container The Bundle in which to save the instance of this Preference.
     * 
     * @see #restoreHierarchyState
     * @see #onSaveInstanceState
     */
    public void saveHierarchyState(Bundle container) {
        dispatchSaveInstanceState(container);
    }

    /**
     * Called by {@link #saveHierarchyState} to store the instance for this Preference and its children.
     * May be overridden to modify how the save happens for children. For example, some
     * Preference objects may want to not store an instance for their children.
     * 
     * @param container The Bundle in which to save the instance of this Preference.
     * 
     * @see #saveHierarchyState
     * @see #onSaveInstanceState
     */
    void dispatchSaveInstanceState(Bundle container) {
        if (hasKey()) {
            mBaseMethodCalled = false;
            Parcelable state = onSaveInstanceState();
            if (!mBaseMethodCalled) {
                throw new IllegalStateException(
                        "Derived class did not call super.onSaveInstanceState()");
            }
            if (state != null) {
                container.putParcelable(mKey, state);
            }
        }
    }

    /**
     * Hook allowing a Preference to generate a representation of its internal
     * state that can later be used to create a new instance with that same
     * state. This state should only contain information that is not persistent
     * or can be reconstructed later.
     * 
     * @return A Parcelable object containing the current dynamic state of
     *         this Preference, or null if there is nothing interesting to save.
     *         The default implementation returns null.
     * @see #onRestoreInstanceState
     * @see #saveHierarchyState
     */
    protected Parcelable onSaveInstanceState() {
        mBaseMethodCalled = true;
        return BaseSavedState.EMPTY_STATE;
    }

    /**
     * Restore this Preference hierarchy's previously saved state from the given container.
     * 
     * @param container The Bundle that holds the previously saved state.
     * 
     * @see #saveHierarchyState
     * @see #onRestoreInstanceState
     */
    public void restoreHierarchyState(Bundle container) {
        dispatchRestoreInstanceState(container);
    }

    /**
     * Called by {@link #restoreHierarchyState} to retrieve the saved state for this
     * Preference and its children. May be overridden to modify how restoring
     * happens to the children of a Preference. For example, some Preference objects may
     * not want to save state for their children.
     * 
     * @param container The Bundle that holds the previously saved state.
     * @see #restoreHierarchyState
     * @see #onRestoreInstanceState
     */
    void dispatchRestoreInstanceState(Bundle container) {
        if (hasKey()) {
            Parcelable state = container.getParcelable(mKey);
            if (state != null) {
                mBaseMethodCalled = false;
                onRestoreInstanceState(state);
                if (!mBaseMethodCalled) {
                    throw new IllegalStateException(
                            "Derived class did not call super.onRestoreInstanceState()");
                }
            }
        }
    }

    /**
     * Hook allowing a Preference to re-apply a representation of its internal
     * state that had previously been generated by {@link #onSaveInstanceState}.
     * This function will never be called with a null state.
     * 
     * @param state The saved state that had previously been returned by
     *            {@link #onSaveInstanceState}.
     * @see #onSaveInstanceState
     * @see #restoreHierarchyState
     */
    protected void onRestoreInstanceState(Parcelable state) {
        mBaseMethodCalled = true;
        if (state != BaseSavedState.EMPTY_STATE && state != null) {
            throw new IllegalArgumentException("Wrong state class -- expecting Preference State");
        }
    }

    /**
     * A base class for managing the instance state of a {@link Preference}.
     */
    public static class BaseSavedState extends AbsSavedState {
        public BaseSavedState(Parcel source) {
            super(source);
        }

        public BaseSavedState(Parcelable superState) {
            super(superState);
        }
        
        public static final Parcelable.Creator<BaseSavedState> CREATOR =
                new Parcelable.Creator<BaseSavedState>() {
            public BaseSavedState createFromParcel(Parcel in) {
                return new BaseSavedState(in);
            }

            public BaseSavedState[] newArray(int size) {
                return new BaseSavedState[size];
            }
        };
    }

}

Other Android examples (source code examples)

Here is a short list of links related to this Android Preference.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.