FileDocCategorySizeDatePackage
PreferenceActivity.javaAPI DocAndroid 5.1 API61697Thu Mar 12 22:22:10 GMT 2015android.preference

PreferenceActivity

public abstract class PreferenceActivity extends android.app.ListActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback
This is the base class for an activity to show a hierarchy of preferences to the user. Prior to {@link android.os.Build.VERSION_CODES#HONEYCOMB} this class only allowed the display of a single set of preference; this functionality should now be found in the new {@link PreferenceFragment} class. If you are using PreferenceActivity in its old mode, the documentation there applies to the deprecated APIs here.

This activity shows one or more headers of preferences, each of which is associated with a {@link PreferenceFragment} to display the preferences of that header. The actual layout and display of these associations can however vary; currently there are two major approaches it may take:

  • On a small screen it may display only the headers as a single list when first launched. Selecting one of the header items will re-launch the activity with it only showing the PreferenceFragment of that header.
  • On a large screen in may display both the headers and current PreferenceFragment together as panes. Selecting a header item switches to showing the correct PreferenceFragment for that item.

Subclasses of PreferenceActivity should implement {@link #onBuildHeaders} to populate the header list with the desired items. Doing this implicitly switches the class into its new "headers + fragments" mode rather than the old style of just showing a single preferences list.

Developer Guides

For information about using {@code PreferenceActivity}, read the Settings guide.

Sample Code

The following sample code shows a simple preference activity that has two different sets of preferences. The implementation, consisting of the activity itself as well as its two preference fragments is:

{@sample development/samples/ApiDemos/src/com/example/android/apis/preference/PreferenceWithHeaders.java activity}

The preference_headers resource describes the headers to be displayed and the fragments associated with them. It is: {@sample development/samples/ApiDemos/res/xml/preference_headers.xml headers}

The first header is shown by Prefs1Fragment, which populates itself from the following XML resource:

{@sample development/samples/ApiDemos/res/xml/fragmented_preferences.xml preferences}

Note that this XML resource contains a preference screen holding another fragment, the Prefs1FragmentInner implemented here. This allows the user to traverse down a hierarchy of preferences; pressing back will pop each fragment off the stack to return to the previous preferences.

See {@link PreferenceFragment} for information on implementing the fragments themselves.

Fields Summary
private static final String
TAG
private static final String
HEADERS_TAG
private static final String
CUR_HEADER_TAG
private static final String
PREFERENCES_TAG
public static final String
EXTRA_SHOW_FRAGMENT
When starting this activity, the invoking Intent can contain this extra string to specify which fragment should be initially displayed.

Starting from Key Lime Pie, when this argument is passed in, the PreferenceActivity will call isValidFragment() to confirm that the fragment class name is valid for this activity.

public static final String
EXTRA_SHOW_FRAGMENT_ARGUMENTS
When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, this extra can also be specified to supply a Bundle of arguments to pass to that fragment when it is instantiated during the initial creation of PreferenceActivity.
public static final String
EXTRA_SHOW_FRAGMENT_TITLE
When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, this extra can also be specify to supply the title to be shown for that fragment.
public static final String
EXTRA_SHOW_FRAGMENT_SHORT_TITLE
When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, this extra can also be specify to supply the short title to be shown for that fragment.
public static final String
EXTRA_NO_HEADERS
When starting this activity, the invoking Intent can contain this extra boolean that the header list should not be displayed. This is most often used in conjunction with {@link #EXTRA_SHOW_FRAGMENT} to launch the activity to display a specific fragment that the user has navigated to.
private static final String
BACK_STACK_PREFS
private static final String
EXTRA_PREFS_SHOW_BUTTON_BAR
private static final String
EXTRA_PREFS_SHOW_SKIP
private static final String
EXTRA_PREFS_SET_NEXT_TEXT
private static final String
EXTRA_PREFS_SET_BACK_TEXT
private final ArrayList
mHeaders
private android.widget.FrameLayout
mListFooter
private android.view.ViewGroup
mPrefsContainer
private android.app.FragmentBreadCrumbs
mFragmentBreadCrumbs
private boolean
mSinglePane
private Header
mCurHeader
private PreferenceManager
mPreferenceManager
private android.os.Bundle
mSavedInstanceState
private android.widget.Button
mNextButton
private int
mPreferenceHeaderItemResId
private boolean
mPreferenceHeaderRemoveEmptyIcon
private static final int
FIRST_REQUEST_CODE
The starting request code given out to preference framework.
private static final int
MSG_BIND_PREFERENCES
private static final int
MSG_BUILD_HEADERS
private android.os.Handler
mHandler
public static final long
HEADER_ID_UNDEFINED
Default value for {@link Header#id Header.id} indicating that no identifier value is set. All other values (including those below -1) are valid.
Constructors Summary
Methods Summary
public voidaddPreferencesFromIntent(android.content.Intent intent)
Adds preferences from activities that match the given {@link Intent}.

param
intent The {@link Intent} to query activities.
deprecated
This function is not relevant for a modern fragment-based PreferenceActivity.

        requirePreferenceManager();

        setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
    
public voidaddPreferencesFromResource(int preferencesResId)
Inflates the given XML resource and adds the preference hierarchy to the current preference hierarchy.

param
preferencesResId The XML resource ID to inflate.
deprecated
This function is not relevant for a modern fragment-based PreferenceActivity.

        requirePreferenceManager();

        setPreferenceScreen(mPreferenceManager.inflateFromResource(this, preferencesResId,
                getPreferenceScreen()));
    
private voidbindPreferences()

        final PreferenceScreen preferenceScreen = getPreferenceScreen();
        if (preferenceScreen != null) {
            preferenceScreen.bind(getListView());
            if (mSavedInstanceState != null) {
                super.onRestoreInstanceState(mSavedInstanceState);
                mSavedInstanceState = null;
            }
        }
    
android.preference.PreferenceActivity$HeaderfindBestMatchingHeader(android.preference.PreferenceActivity$Header cur, java.util.ArrayList from)

        ArrayList<Header> matches = new ArrayList<Header>();
        for (int j=0; j<from.size(); j++) {
            Header oh = from.get(j);
            if (cur == oh || (cur.id != HEADER_ID_UNDEFINED && cur.id == oh.id)) {
                // Must be this one.
                matches.clear();
                matches.add(oh);
                break;
            }
            if (cur.fragment != null) {
                if (cur.fragment.equals(oh.fragment)) {
                    matches.add(oh);
                }
            } else if (cur.intent != null) {
                if (cur.intent.equals(oh.intent)) {
                    matches.add(oh);
                }
            } else if (cur.title != null) {
                if (cur.title.equals(oh.title)) {
                    matches.add(oh);
                }
            }
        }
        final int NM = matches.size();
        if (NM == 1) {
            return matches.get(0);
        } else if (NM > 1) {
            for (int j=0; j<NM; j++) {
                Header oh = matches.get(j);
                if (cur.fragmentArguments != null &&
                        cur.fragmentArguments.equals(oh.fragmentArguments)) {
                    return oh;
                }
                if (cur.extras != null && cur.extras.equals(oh.extras)) {
                    return oh;
                }
                if (cur.title != null && cur.title.equals(oh.title)) {
                    return oh;
                }
            }
        }
        return null;
    
public PreferencefindPreference(java.lang.CharSequence key)
Finds a {@link Preference} based on its key.

param
key The key of the preference to retrieve.
return
The {@link Preference} with the key, or null.
see
PreferenceGroup#findPreference(CharSequence)
deprecated
This function is not relevant for a modern fragment-based PreferenceActivity.


        if (mPreferenceManager == null) {
            return null;
        }

        return mPreferenceManager.findPreference(key);
    
public voidfinishPreferencePanel(android.app.Fragment caller, int resultCode, android.content.Intent resultData)
Called by a preference panel fragment to finish itself.

param
caller The fragment that is asking to be finished.
param
resultCode Optional result code to send back to the original launching fragment.
param
resultData Optional result data to send back to the original launching fragment.

        if (mSinglePane) {
            setResult(resultCode, resultData);
            finish();
        } else {
            // XXX be smarter about popping the stack.
            onBackPressed();
            if (caller != null) {
                if (caller.getTargetFragment() != null) {
                    caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
                            resultCode, resultData);
                }
            }
        }
    
public java.util.ListgetHeaders()
Returns the Header list

hide

        return mHeaders;
    
protected android.widget.ButtongetNextButton()

hide

        return mNextButton;
    
public PreferenceManagergetPreferenceManager()
Returns the {@link PreferenceManager} used by this activity.

return
The {@link PreferenceManager}.
deprecated
This function is not relevant for a modern fragment-based PreferenceActivity.

        return mPreferenceManager;
    
public PreferenceScreengetPreferenceScreen()
Gets the root of the preference hierarchy that this activity is showing.

return
The {@link PreferenceScreen} that is the root of the preference hierarchy.
deprecated
This function is not relevant for a modern fragment-based PreferenceActivity.

        if (mPreferenceManager != null) {
            return mPreferenceManager.getPreferenceScreen();
        }
        return null;
    
public booleanhasHeaders()
Returns true if this activity is currently showing the header list.

        return getListView().getVisibility() == View.VISIBLE
                && mPreferenceManager == null;
    
protected booleanhasNextButton()

hide

        return mNextButton != null;
    
public voidinvalidateHeaders()
Call when you need to change the headers being displayed. Will result in onBuildHeaders() later being called to retrieve the new list.

        if (!mHandler.hasMessages(MSG_BUILD_HEADERS)) {
            mHandler.sendEmptyMessage(MSG_BUILD_HEADERS);
        }
    
public booleanisMultiPane()
Returns true if this activity is showing multiple panes -- the headers and a preference fragment.

        return hasHeaders() && mPrefsContainer.getVisibility() == View.VISIBLE;
    
protected booleanisValidFragment(java.lang.String fragmentName)
Subclasses should override this method and verify that the given fragment is a valid type to be attached to this activity. The default implementation returns true for apps built for android:targetSdkVersion older than {@link android.os.Build.VERSION_CODES#KITKAT}. For later versions, it will throw an exception.

param
fragmentName the class name of the Fragment about to be attached to this activity.
return
true if the fragment class name is valid for this Activity and false otherwise.

        if (getApplicationInfo().targetSdkVersion  >= android.os.Build.VERSION_CODES.KITKAT) {
            throw new RuntimeException(
                    "Subclasses of PreferenceActivity must override isValidFragment(String)"
                    + " to verify that the Fragment class is valid! " + this.getClass().getName()
                    + " has not checked if fragment " + fragmentName + " is valid.");
        } else {
            return true;
        }
    
public voidloadHeadersFromResource(int resid, java.util.List target)
Parse the given XML file as a header description, adding each parsed Header into the target list.

param
resid The XML resource to load and parse.
param
target The list in which the parsed headers should be placed.

        XmlResourceParser parser = null;
        try {
            parser = getResources().getXml(resid);
            AttributeSet attrs = Xml.asAttributeSet(parser);

            int type;
            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && type != XmlPullParser.START_TAG) {
                // Parse next until start tag is found
            }

            String nodeName = parser.getName();
            if (!"preference-headers".equals(nodeName)) {
                throw new RuntimeException(
                        "XML document must start with <preference-headers> tag; found"
                        + nodeName + " at " + parser.getPositionDescription());
            }

            Bundle curBundle = null;

            final int outerDepth = parser.getDepth();
            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                    continue;
                }

                nodeName = parser.getName();
                if ("header".equals(nodeName)) {
                    Header header = new Header();

                    TypedArray sa = obtainStyledAttributes(
                            attrs, com.android.internal.R.styleable.PreferenceHeader);
                    header.id = sa.getResourceId(
                            com.android.internal.R.styleable.PreferenceHeader_id,
                            (int)HEADER_ID_UNDEFINED);
                    TypedValue tv = sa.peekValue(
                            com.android.internal.R.styleable.PreferenceHeader_title);
                    if (tv != null && tv.type == TypedValue.TYPE_STRING) {
                        if (tv.resourceId != 0) {
                            header.titleRes = tv.resourceId;
                        } else {
                            header.title = tv.string;
                        }
                    }
                    tv = sa.peekValue(
                            com.android.internal.R.styleable.PreferenceHeader_summary);
                    if (tv != null && tv.type == TypedValue.TYPE_STRING) {
                        if (tv.resourceId != 0) {
                            header.summaryRes = tv.resourceId;
                        } else {
                            header.summary = tv.string;
                        }
                    }
                    tv = sa.peekValue(
                            com.android.internal.R.styleable.PreferenceHeader_breadCrumbTitle);
                    if (tv != null && tv.type == TypedValue.TYPE_STRING) {
                        if (tv.resourceId != 0) {
                            header.breadCrumbTitleRes = tv.resourceId;
                        } else {
                            header.breadCrumbTitle = tv.string;
                        }
                    }
                    tv = sa.peekValue(
                            com.android.internal.R.styleable.PreferenceHeader_breadCrumbShortTitle);
                    if (tv != null && tv.type == TypedValue.TYPE_STRING) {
                        if (tv.resourceId != 0) {
                            header.breadCrumbShortTitleRes = tv.resourceId;
                        } else {
                            header.breadCrumbShortTitle = tv.string;
                        }
                    }
                    header.iconRes = sa.getResourceId(
                            com.android.internal.R.styleable.PreferenceHeader_icon, 0);
                    header.fragment = sa.getString(
                            com.android.internal.R.styleable.PreferenceHeader_fragment);
                    sa.recycle();

                    if (curBundle == null) {
                        curBundle = new Bundle();
                    }

                    final int innerDepth = parser.getDepth();
                    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                           && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                            continue;
                        }

                        String innerNodeName = parser.getName();
                        if (innerNodeName.equals("extra")) {
                            getResources().parseBundleExtra("extra", attrs, curBundle);
                            XmlUtils.skipCurrentTag(parser);

                        } else if (innerNodeName.equals("intent")) {
                            header.intent = Intent.parseIntent(getResources(), parser, attrs);

                        } else {
                            XmlUtils.skipCurrentTag(parser);
                        }
                    }

                    if (curBundle.size() > 0) {
                        header.fragmentArguments = curBundle;
                        curBundle = null;
                    }

                    target.add(header);
                } else {
                    XmlUtils.skipCurrentTag(parser);
                }
            }

        } catch (XmlPullParserException e) {
            throw new RuntimeException("Error parsing headers", e);
        } catch (IOException e) {
            throw new RuntimeException("Error parsing headers", e);
        } finally {
            if (parser != null) parser.close();
        }
    
protected voidonActivityResult(int requestCode, int resultCode, android.content.Intent data)

        super.onActivityResult(requestCode, resultCode, data);

        if (mPreferenceManager != null) {
            mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
        }
    
public voidonBuildHeaders(java.util.List target)
Called when the activity needs its list of headers build. By implementing this and adding at least one item to the list, you will cause the activity to run in its modern fragment mode. Note that this function may not always be called; for example, if the activity has been asked to display a particular fragment without the header list, there is no need to build the headers.

Typical implementations will use {@link #loadHeadersFromResource} to fill in the list from a resource.

param
target The list in which to place the headers.

        // Should be overloaded by subclasses
    
public android.content.IntentonBuildStartFragmentIntent(java.lang.String fragmentName, android.os.Bundle args, int titleRes, int shortTitleRes)
Called by {@link #startWithFragment(String, Bundle, Fragment, int, int, int)} when in single-pane mode, to build an Intent to launch a new activity showing the selected fragment. The default implementation constructs an Intent that re-launches the current activity with the appropriate arguments to display the fragment.

param
fragmentName The name of the fragment to display.
param
args Optional arguments to supply to the fragment.
param
titleRes Optional resource ID of title to show for this item.
param
shortTitleRes Optional resource ID of short title to show for this item.
return
Returns an Intent that can be launched to display the given fragment.

        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setClass(this, getClass());
        intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
        intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
        intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, titleRes);
        intent.putExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, shortTitleRes);
        intent.putExtra(EXTRA_NO_HEADERS, true);
        return intent;
    
public voidonContentChanged()

        super.onContentChanged();

        if (mPreferenceManager != null) {
            postBindPreferences();
        }
    
protected voidonCreate(android.os.Bundle savedInstanceState)

    

    
        
        super.onCreate(savedInstanceState);

        // Theming for the PreferenceActivity layout and for the Preference Header(s) layout
        TypedArray sa = obtainStyledAttributes(null,
                com.android.internal.R.styleable.PreferenceActivity,
                com.android.internal.R.attr.preferenceActivityStyle,
                0);

        final int layoutResId = sa.getResourceId(
                com.android.internal.R.styleable.PreferenceActivity_layout,
                com.android.internal.R.layout.preference_list_content);

        mPreferenceHeaderItemResId = sa.getResourceId(
                com.android.internal.R.styleable.PreferenceActivity_headerLayout,
                com.android.internal.R.layout.preference_header_item);
        mPreferenceHeaderRemoveEmptyIcon = sa.getBoolean(
                com.android.internal.R.styleable.PreferenceActivity_headerRemoveIconIfEmpty,
                false);

        sa.recycle();

        setContentView(layoutResId);

        mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer);
        mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs_frame);
        boolean hidingHeaders = onIsHidingHeaders();
        mSinglePane = hidingHeaders || !onIsMultiPane();
        String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
        Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
        int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);
        int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);

        if (savedInstanceState != null) {
            // We are restarting from a previous saved state; used that to
            // initialize, instead of starting fresh.
            ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG);
            if (headers != null) {
                mHeaders.addAll(headers);
                int curHeader = savedInstanceState.getInt(CUR_HEADER_TAG,
                        (int) HEADER_ID_UNDEFINED);
                if (curHeader >= 0 && curHeader < mHeaders.size()) {
                    setSelectedHeader(mHeaders.get(curHeader));
                }
            }

        } else {
            if (initialFragment != null && mSinglePane) {
                // If we are just showing a fragment, we want to run in
                // new fragment mode, but don't need to compute and show
                // the headers.
                switchToHeader(initialFragment, initialArguments);
                if (initialTitle != 0) {
                    CharSequence initialTitleStr = getText(initialTitle);
                    CharSequence initialShortTitleStr = initialShortTitle != 0
                            ? getText(initialShortTitle) : null;
                    showBreadCrumbs(initialTitleStr, initialShortTitleStr);
                }

            } else {
                // We need to try to build the headers.
                onBuildHeaders(mHeaders);

                // If there are headers, then at this point we need to show
                // them and, depending on the screen, we may also show in-line
                // the currently selected preference fragment.
                if (mHeaders.size() > 0) {
                    if (!mSinglePane) {
                        if (initialFragment == null) {
                            Header h = onGetInitialHeader();
                            switchToHeader(h);
                        } else {
                            switchToHeader(initialFragment, initialArguments);
                        }
                    }
                }
            }
        }

        // The default configuration is to only show the list view.  Adjust
        // visibility for other configurations.
        if (initialFragment != null && mSinglePane) {
            // Single pane, showing just a prefs fragment.
            findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
            mPrefsContainer.setVisibility(View.VISIBLE);
            if (initialTitle != 0) {
                CharSequence initialTitleStr = getText(initialTitle);
                CharSequence initialShortTitleStr = initialShortTitle != 0
                        ? getText(initialShortTitle) : null;
                showBreadCrumbs(initialTitleStr, initialShortTitleStr);
            }
        } else if (mHeaders.size() > 0) {
            setListAdapter(new HeaderAdapter(this, mHeaders, mPreferenceHeaderItemResId,
                    mPreferenceHeaderRemoveEmptyIcon));
            if (!mSinglePane) {
                // Multi-pane.
                getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
                if (mCurHeader != null) {
                    setSelectedHeader(mCurHeader);
                }
                mPrefsContainer.setVisibility(View.VISIBLE);
            }
        } else {
            // If there are no headers, we are in the old "just show a screen
            // of preferences" mode.
            setContentView(com.android.internal.R.layout.preference_list_content_single);
            mListFooter = (FrameLayout) findViewById(com.android.internal.R.id.list_footer);
            mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs);
            mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
            mPreferenceManager.setOnPreferenceTreeClickListener(this);
        }

        // see if we should show Back/Next buttons
        Intent intent = getIntent();
        if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {

            findViewById(com.android.internal.R.id.button_bar).setVisibility(View.VISIBLE);

            Button backButton = (Button)findViewById(com.android.internal.R.id.back_button);
            backButton.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    setResult(RESULT_CANCELED);
                    finish();
                }
            });
            Button skipButton = (Button)findViewById(com.android.internal.R.id.skip_button);
            skipButton.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    setResult(RESULT_OK);
                    finish();
                }
            });
            mNextButton = (Button)findViewById(com.android.internal.R.id.next_button);
            mNextButton.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    setResult(RESULT_OK);
                    finish();
                }
            });

            // set our various button parameters
            if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
                String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
                if (TextUtils.isEmpty(buttonText)) {
                    mNextButton.setVisibility(View.GONE);
                }
                else {
                    mNextButton.setText(buttonText);
                }
            }
            if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
                String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
                if (TextUtils.isEmpty(buttonText)) {
                    backButton.setVisibility(View.GONE);
                }
                else {
                    backButton.setText(buttonText);
                }
            }
            if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
                skipButton.setVisibility(View.VISIBLE);
            }
        }
    
protected voidonDestroy()

        mHandler.removeMessages(MSG_BIND_PREFERENCES);
        mHandler.removeMessages(MSG_BUILD_HEADERS);
        super.onDestroy();

        if (mPreferenceManager != null) {
            mPreferenceManager.dispatchActivityDestroy();
        }
    
public android.preference.PreferenceActivity$HeaderonGetInitialHeader()
Called to determine the initial header to be shown. The default implementation simply returns the fragment of the first header. Note that the returned Header object does not actually need to exist in your header list -- whatever its fragment is will simply be used to show for the initial UI.

        for (int i=0; i<mHeaders.size(); i++) {
            Header h = mHeaders.get(i);
            if (h.fragment != null) {
                return h;
            }
        }
        throw new IllegalStateException("Must have at least one header with a fragment");
    
public android.preference.PreferenceActivity$HeaderonGetNewHeader()
Called after the header list has been updated ({@link #onBuildHeaders} has been called and returned due to {@link #invalidateHeaders()}) to specify the header that should now be selected. The default implementation returns null to keep whatever header is currently selected.

        return null;
    
public voidonHeaderClick(android.preference.PreferenceActivity$Header header, int position)
Called when the user selects an item in the header list. The default implementation will call either {@link #startWithFragment(String, Bundle, Fragment, int, int, int)} or {@link #switchToHeader(Header)} as appropriate.

param
header The header that was selected.
param
position The header's position in the list.

        if (header.fragment != null) {
            if (mSinglePane) {
                int titleRes = header.breadCrumbTitleRes;
                int shortTitleRes = header.breadCrumbShortTitleRes;
                if (titleRes == 0) {
                    titleRes = header.titleRes;
                    shortTitleRes = 0;
                }
                startWithFragment(header.fragment, header.fragmentArguments, null, 0,
                        titleRes, shortTitleRes);
            } else {
                switchToHeader(header);
            }
        } else if (header.intent != null) {
            startActivity(header.intent);
        }
    
public booleanonIsHidingHeaders()
Called to determine whether the header list should be hidden. The default implementation returns the value given in {@link #EXTRA_NO_HEADERS} or false if it is not supplied. This is set to false, for example, when the activity is being re-launched to show a particular preference activity.

        return getIntent().getBooleanExtra(EXTRA_NO_HEADERS, false);
    
public booleanonIsMultiPane()
Called to determine if the activity should run in multi-pane mode. The default implementation returns true if the screen is large enough.

        boolean preferMultiPane = getResources().getBoolean(
                com.android.internal.R.bool.preferences_prefer_dual_pane);
        return preferMultiPane;
    
protected voidonListItemClick(android.widget.ListView l, android.view.View v, int position, long id)

        if (!isResumed()) {
            return;
        }
        super.onListItemClick(l, v, position, id);

        if (mAdapter != null) {
            Object item = mAdapter.getItem(position);
            if (item instanceof Header) onHeaderClick((Header) item, position);
        }
    
protected voidonNewIntent(android.content.Intent intent)

        if (mPreferenceManager != null) {
            mPreferenceManager.dispatchNewIntent(intent);
        }
    
public booleanonPreferenceStartFragment(PreferenceFragment caller, Preference pref)

        startPreferencePanel(pref.getFragment(), pref.getExtras(), pref.getTitleRes(),
                pref.getTitle(), null, 0);
        return true;
    
public booleanonPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
{@inheritDoc}

deprecated
This function is not relevant for a modern fragment-based PreferenceActivity.

        return false;
    
protected voidonRestoreInstanceState(android.os.Bundle state)

        if (mPreferenceManager != null) {
            Bundle container = state.getBundle(PREFERENCES_TAG);
            if (container != null) {
                final PreferenceScreen preferenceScreen = getPreferenceScreen();
                if (preferenceScreen != null) {
                    preferenceScreen.restoreHierarchyState(container);
                    mSavedInstanceState = state;
                    return;
                }
            }
        }

        // Only call this if we didn't save the instance state for later.
        // If we did save it, it will be restored when we bind the adapter.
        super.onRestoreInstanceState(state);
    
protected voidonSaveInstanceState(android.os.Bundle outState)

        super.onSaveInstanceState(outState);

        if (mHeaders.size() > 0) {
            outState.putParcelableArrayList(HEADERS_TAG, mHeaders);
            if (mCurHeader != null) {
                int index = mHeaders.indexOf(mCurHeader);
                if (index >= 0) {
                    outState.putInt(CUR_HEADER_TAG, index);
                }
            }
        }

        if (mPreferenceManager != null) {
            final PreferenceScreen preferenceScreen = getPreferenceScreen();
            if (preferenceScreen != null) {
                Bundle container = new Bundle();
                preferenceScreen.saveHierarchyState(container);
                outState.putBundle(PREFERENCES_TAG, container);
            }
        }
    
protected voidonStop()

        super.onStop();

        if (mPreferenceManager != null) {
            mPreferenceManager.dispatchActivityStop();
        }
    
private voidpostBindPreferences()
Posts a message to bind the preferences to the list view.

Binding late is preferred as any custom preference types created in {@link #onCreate(Bundle)} are able to have their views recycled.

        if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
        mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
    
private voidrequirePreferenceManager()

        if (mPreferenceManager == null) {
            if (mAdapter == null) {
                throw new RuntimeException("This should be called after super.onCreate.");
            }
            throw new RuntimeException(
                    "Modern two-pane PreferenceActivity requires use of a PreferenceFragment");
        }
    
public voidsetListFooter(android.view.View view)
Set a footer that should be shown at the bottom of the header list.

        mListFooter.removeAllViews();
        mListFooter.addView(view, new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.WRAP_CONTENT));
    
public voidsetParentTitle(java.lang.CharSequence title, java.lang.CharSequence shortTitle, android.view.View.OnClickListener listener)
Should be called after onCreate to ensure that the breadcrumbs, if any, were created. This prepends a title to the fragment breadcrumbs and attaches a listener to any clicks on the parent entry.

param
title the title for the breadcrumb
param
shortTitle the short title for the breadcrumb

        if (mFragmentBreadCrumbs != null) {
            mFragmentBreadCrumbs.setParentTitle(title, shortTitle, listener);
        }
    
public voidsetPreferenceScreen(PreferenceScreen preferenceScreen)
Sets the root of the preference hierarchy that this activity is showing.

param
preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
deprecated
This function is not relevant for a modern fragment-based PreferenceActivity.

        requirePreferenceManager();

        if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
            postBindPreferences();
            CharSequence title = getPreferenceScreen().getTitle();
            // Set the title of the activity
            if (title != null) {
                setTitle(title);
            }
        }
    
voidsetSelectedHeader(android.preference.PreferenceActivity$Header header)

        mCurHeader = header;
        int index = mHeaders.indexOf(header);
        if (index >= 0) {
            getListView().setItemChecked(index, true);
        } else {
            getListView().clearChoices();
        }
        showBreadCrumbs(header);
    
public voidshowBreadCrumbs(java.lang.CharSequence title, java.lang.CharSequence shortTitle)
Change the base title of the bread crumbs for the current preferences. This will normally be called for you. See {@link android.app.FragmentBreadCrumbs} for more information.

        if (mFragmentBreadCrumbs == null) {
            View crumbs = findViewById(android.R.id.title);
            // For screens with a different kind of title, don't create breadcrumbs.
            try {
                mFragmentBreadCrumbs = (FragmentBreadCrumbs)crumbs;
            } catch (ClassCastException e) {
                setTitle(title);
                return;
            }
            if (mFragmentBreadCrumbs == null) {
                if (title != null) {
                    setTitle(title);
                }
                return;
            }
            if (mSinglePane) {
                mFragmentBreadCrumbs.setVisibility(View.GONE);
                // Hide the breadcrumb section completely for single-pane
                View bcSection = findViewById(com.android.internal.R.id.breadcrumb_section);
                if (bcSection != null) bcSection.setVisibility(View.GONE);
                setTitle(title);
            }
            mFragmentBreadCrumbs.setMaxVisible(2);
            mFragmentBreadCrumbs.setActivity(this);
        }
        if (mFragmentBreadCrumbs.getVisibility() != View.VISIBLE) {
            setTitle(title);
        } else {
            mFragmentBreadCrumbs.setTitle(title, shortTitle);
            mFragmentBreadCrumbs.setParentTitle(null, null, null);
        }
    
voidshowBreadCrumbs(android.preference.PreferenceActivity$Header header)

        if (header != null) {
            CharSequence title = header.getBreadCrumbTitle(getResources());
            if (title == null) title = header.getTitle(getResources());
            if (title == null) title = getTitle();
            showBreadCrumbs(title, header.getBreadCrumbShortTitle(getResources()));
        } else {
            showBreadCrumbs(getTitle(), null);
        }
    
public voidstartPreferenceFragment(android.app.Fragment fragment, boolean push)
Start a new fragment.

param
fragment The fragment to start
param
push If true, the current fragment will be pushed onto the back stack. If false, the current fragment will be replaced.

        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(com.android.internal.R.id.prefs, fragment);
        if (push) {
            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            transaction.addToBackStack(BACK_STACK_PREFS);
        } else {
            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        }
        transaction.commitAllowingStateLoss();
    
public voidstartPreferencePanel(java.lang.String fragmentClass, android.os.Bundle args, int titleRes, java.lang.CharSequence titleText, android.app.Fragment resultTo, int resultRequestCode)
Start a new fragment containing a preference panel. If the preferences are being displayed in multi-pane mode, the given fragment class will be instantiated and placed in the appropriate pane. If running in single-pane mode, a new activity will be launched in which to show the fragment.

param
fragmentClass Full name of the class implementing the fragment.
param
args Any desired arguments to supply to the fragment.
param
titleRes Optional resource identifier of the title of this fragment.
param
titleText Optional text of the title of this fragment.
param
resultTo Optional fragment that result data should be sent to. If non-null, resultTo.onActivityResult() will be called when this preference panel is done. The launched panel must use {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
param
resultRequestCode If resultTo is non-null, this is the caller's request code to be received with the resut.

        if (mSinglePane) {
            startWithFragment(fragmentClass, args, resultTo, resultRequestCode, titleRes, 0);
        } else {
            Fragment f = Fragment.instantiate(this, fragmentClass, args);
            if (resultTo != null) {
                f.setTargetFragment(resultTo, resultRequestCode);
            }
            FragmentTransaction transaction = getFragmentManager().beginTransaction();
            transaction.replace(com.android.internal.R.id.prefs, f);
            if (titleRes != 0) {
                transaction.setBreadCrumbTitle(titleRes);
            } else if (titleText != null) {
                transaction.setBreadCrumbTitle(titleText);
            }
            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
            transaction.addToBackStack(BACK_STACK_PREFS);
            transaction.commitAllowingStateLoss();
        }
    
public voidstartWithFragment(java.lang.String fragmentName, android.os.Bundle args, android.app.Fragment resultTo, int resultRequestCode)
Like {@link #startWithFragment(String, Bundle, Fragment, int, int, int)} but uses a 0 titleRes.

        startWithFragment(fragmentName, args, resultTo, resultRequestCode, 0, 0);
    
public voidstartWithFragment(java.lang.String fragmentName, android.os.Bundle args, android.app.Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes)
Start a new instance of this activity, showing only the given preference fragment. When launched in this mode, the header list will be hidden and the given preference fragment will be instantiated and fill the entire activity.

param
fragmentName The name of the fragment to display.
param
args Optional arguments to supply to the fragment.
param
resultTo Option fragment that should receive the result of the activity launch.
param
resultRequestCode If resultTo is non-null, this is the request code in which to report the result.
param
titleRes Resource ID of string to display for the title of this set of preferences.
param
shortTitleRes Resource ID of string to display for the short title of this set of preferences.

        Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
        if (resultTo == null) {
            startActivity(intent);
        } else {
            resultTo.startActivityForResult(intent, resultRequestCode);
        }
    
public voidswitchToHeader(java.lang.String fragmentName, android.os.Bundle args)
When in two-pane mode, switch the fragment pane to show the given preference fragment.

param
fragmentName The name of the fragment to display.
param
args Optional arguments to supply to the fragment.

        Header selectedHeader = null;
        for (int i = 0; i < mHeaders.size(); i++) {
            if (fragmentName.equals(mHeaders.get(i).fragment)) {
                selectedHeader = mHeaders.get(i);
                break;
            }
        }
        setSelectedHeader(selectedHeader);
        switchToHeaderInner(fragmentName, args);
    
public voidswitchToHeader(android.preference.PreferenceActivity$Header header)
When in two-pane mode, switch to the fragment pane to show the given preference fragment.

param
header The new header to display.

        if (mCurHeader == header) {
            // This is the header we are currently displaying.  Just make sure
            // to pop the stack up to its root state.
            getFragmentManager().popBackStack(BACK_STACK_PREFS,
                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
        } else {
            if (header.fragment == null) {
                throw new IllegalStateException("can't switch to header that has no fragment");
            }
            switchToHeaderInner(header.fragment, header.fragmentArguments);
            setSelectedHeader(header);
        }
    
private voidswitchToHeaderInner(java.lang.String fragmentName, android.os.Bundle args)

        getFragmentManager().popBackStack(BACK_STACK_PREFS,
                FragmentManager.POP_BACK_STACK_INCLUSIVE);
        if (!isValidFragment(fragmentName)) {
            throw new IllegalArgumentException("Invalid fragment for this activity: "
                    + fragmentName);
        }
        Fragment f = Fragment.instantiate(this, fragmentName, args);
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        transaction.replace(com.android.internal.R.id.prefs, f);
        transaction.commitAllowingStateLoss();