PreferenceActivity.java revision 09dbf1844016682ed461d080e32a43d0086e767d
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.preference;
18
19import com.android.internal.util.XmlUtils;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23
24import android.app.Fragment;
25import android.app.ListActivity;
26import android.content.Context;
27import android.content.Intent;
28import android.content.res.Configuration;
29import android.content.res.TypedArray;
30import android.content.res.XmlResourceParser;
31import android.graphics.drawable.Drawable;
32import android.os.Bundle;
33import android.os.Handler;
34import android.os.Message;
35import android.text.TextUtils;
36import android.util.AttributeSet;
37import android.util.Log;
38import android.util.Xml;
39import android.view.LayoutInflater;
40import android.view.View;
41import android.view.ViewGroup;
42import android.view.View.OnClickListener;
43import android.widget.ArrayAdapter;
44import android.widget.Button;
45import android.widget.ImageView;
46import android.widget.ListView;
47import android.widget.TextView;
48
49import java.io.IOException;
50import java.util.ArrayList;
51import java.util.List;
52
53/**
54 * This is the base class for an activity to show a hierarchy of preferences
55 * to the user.  Prior to {@link android.os.Build.VERSION_CODES#HONEYCOMB}
56 * this class only allowed the display of a single set of preference; this
57 * functionality should now be found in the new {@link PreferenceFragment}
58 * class.  If you are using PreferenceActivity in its old mode, the documentation
59 * there applies to the deprecated APIs here.
60 *
61 * <p>This activity shows one or more headers of preferences, each of with
62 * is associated with a {@link PreferenceFragment} to display the preferences
63 * of that header.  The actual layout and display of these associations can
64 * however vary; currently there are two major approaches it may take:
65 *
66 * <ul>
67 * <li>On a small screen it may display only the headers as a single list
68 * when first launched.  Selecting one of the header items will re-launch
69 * the activity with it only showing the PreferenceFragment of that header.
70 * <li>On a large screen in may display both the headers and current
71 * PreferenceFragment together as panes.  Selecting a header item switches
72 * to showing the correct PreferenceFragment for that item.
73 * </ul>
74 *
75 * <p>Subclasses of PreferenceActivity should implement
76 * {@link #onBuildHeaders} to populate the header list with the desired
77 * items.  Doing this implicitly switches the class into its new "headers
78 * + fragments" mode rather than the old style of just showing a single
79 * preferences list.
80 *
81 * <a name="SampleCode"></a>
82 * <h3>Sample Code</h3>
83 *
84 * <p>The following sample code shows a simple preference activity that
85 * has two different sets of preferences.  The implementation, consisting
86 * of the activity itself as well as its two preference fragments is:</p>
87 *
88 * {@sample development/samples/ApiDemos/src/com/example/android/apis/preference/PreferenceWithHeaders.java
89 *      activity}
90 *
91 * <p>The preference_headers resource describes the headers to be displayed
92 * and the fragments associated with them.  It is:
93 *
94 * {@sample development/samples/ApiDemos/res/xml/preference_headers.xml headers}
95 *
96 * <p>The first header is shown by Prefs1Fragment, which populates itself
97 * from the following XML resource:</p>
98 *
99 * {@sample development/samples/ApiDemos/res/xml/fragmented_preferences.xml preferences}
100 *
101 * <p>Note that this XML resource contains a preference screen holding another
102 * fragment, the Prefs1FragmentInner implemented here.  This allows the user
103 * to traverse down a hierarchy of preferences; pressing back will pop each
104 * fragment off the stack to return to the previous preferences.
105 *
106 * <p>See {@link PreferenceFragment} for information on implementing the
107 * fragments themselves.
108 */
109public abstract class PreferenceActivity extends ListActivity implements
110        PreferenceManager.OnPreferenceTreeClickListener,
111        PreferenceFragment.OnPreferenceStartFragmentCallback {
112    private static final String TAG = "PreferenceActivity";
113
114    private static final String PREFERENCES_TAG = "android:preferences";
115
116    private static final String EXTRA_PREFS_SHOW_FRAGMENT = ":android:show_fragment";
117
118    private static final String EXTRA_PREFS_NO_HEADERS = ":android:no_headers";
119
120    private static final String BACK_STACK_PREFS = ":android:prefs";
121
122    // extras that allow any preference activity to be launched as part of a wizard
123
124    // show Back and Next buttons? takes boolean parameter
125    // Back will then return RESULT_CANCELED and Next RESULT_OK
126    private static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
127
128    // add a Skip button?
129    private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip";
130
131    // specify custom text for the Back or Next buttons, or cause a button to not appear
132    // at all by setting it to null
133    private static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
134    private static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
135
136    // --- State for new mode when showing a list of headers + prefs fragment
137
138    private final ArrayList<Header> mHeaders = new ArrayList<Header>();
139
140    private HeaderAdapter mAdapter;
141
142    private View mPrefsContainer;
143
144    private boolean mSinglePane;
145
146    // --- State for old mode when showing a single preference list
147
148    private PreferenceManager mPreferenceManager;
149
150    private Bundle mSavedInstanceState;
151
152    // --- Common state
153
154    private Button mNextButton;
155
156    /**
157     * The starting request code given out to preference framework.
158     */
159    private static final int FIRST_REQUEST_CODE = 100;
160
161    private static final int MSG_BIND_PREFERENCES = 0;
162    private Handler mHandler = new Handler() {
163        @Override
164        public void handleMessage(Message msg) {
165            switch (msg.what) {
166
167                case MSG_BIND_PREFERENCES:
168                    bindPreferences();
169                    break;
170            }
171        }
172    };
173
174    private class HeaderViewHolder {
175        ImageView icon;
176        TextView title;
177        TextView summary;
178    }
179
180    private class HeaderAdapter extends ArrayAdapter<Header> {
181        private LayoutInflater mInflater;
182
183        public HeaderAdapter(Context context, List<Header> objects) {
184            super(context, 0, objects);
185            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
186        }
187
188        @Override
189        public View getView(int position, View convertView, ViewGroup parent) {
190            HeaderViewHolder holder;
191            View view;
192
193            if (convertView == null) {
194                view = mInflater.inflate(com.android.internal.R.layout.preference_list_item,
195                        parent, false);
196                holder = new HeaderViewHolder();
197                holder.icon = (ImageView)view.findViewById(
198                        com.android.internal.R.id.icon);
199                holder.title = (TextView)view.findViewById(
200                        com.android.internal.R.id.title);
201                holder.summary = (TextView)view.findViewById(
202                        com.android.internal.R.id.summary);
203                view.setTag(holder);
204            } else {
205                view = convertView;
206                holder = (HeaderViewHolder)view.getTag();
207            }
208
209            Header header = getItem(position);
210            if (header.icon != null) holder.icon.setImageDrawable(header.icon);
211            else if (header.iconRes != 0) holder.icon.setImageResource(header.iconRes);
212            if (header.title != null) holder.title.setText(header.title);
213            if (header.summary != null) holder.summary.setText(header.summary);
214
215            return view;
216        }
217    }
218
219    /**
220     * Description of a single Header item that the user can select.
221     */
222    public static class Header {
223        /**
224         * Title of the header that is shown to the user.
225         * @attr ref android.R.styleable#PreferenceHeader_title
226         */
227        CharSequence title;
228
229        /**
230         * Optional summary describing what this header controls.
231         * @attr ref android.R.styleable#PreferenceHeader_summary
232         */
233        CharSequence summary;
234
235        /**
236         * Optional icon resource to show for this header.
237         * @attr ref android.R.styleable#PreferenceHeader_icon
238         */
239        int iconRes;
240
241        /**
242         * Optional icon drawable to show for this header.  (If this is non-null,
243         * the iconRes will be ignored.)
244         */
245        Drawable icon;
246
247        /**
248         * Full class name of the fragment to display when this header is
249         * selected.
250         * @attr ref android.R.styleable#PreferenceHeader_fragment
251         */
252        String fragment;
253    }
254
255    @Override
256    protected void onCreate(Bundle savedInstanceState) {
257        super.onCreate(savedInstanceState);
258
259        setContentView(com.android.internal.R.layout.preference_list_content);
260
261        mPrefsContainer = findViewById(com.android.internal.R.id.prefs);
262        boolean hidingHeaders = onIsHidingHeaders();
263        mSinglePane = hidingHeaders || !onIsMultiPane();
264        String initialFragment = getIntent().getStringExtra(EXTRA_PREFS_SHOW_FRAGMENT);
265
266        if (initialFragment != null && mSinglePane) {
267            // If we are just showing a fragment, we want to run in
268            // new fragment mode, but don't need to compute and show
269            // the headers.
270            getListView().setVisibility(View.GONE);
271            mPrefsContainer.setVisibility(View.VISIBLE);
272            switchToHeader(initialFragment);
273
274        } else {
275            // We need to try to build the headers.
276            onBuildHeaders(mHeaders);
277
278            // If there are headers, then at this point we need to show
279            // them and, depending on the screen, we may also show in-line
280            // the currently selected preference fragment.
281            if (mHeaders.size() > 0) {
282                mAdapter = new HeaderAdapter(this, mHeaders);
283                setListAdapter(mAdapter);
284                if (!mSinglePane) {
285                    mPrefsContainer.setVisibility(View.VISIBLE);
286                    switchToHeader(initialFragment != null
287                            ? initialFragment : onGetInitialFragment());
288                }
289
290            // If there are no headers, we are in the old "just show a screen
291            // of preferences" mode.
292            } else {
293                mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
294                mPreferenceManager.setOnPreferenceTreeClickListener(this);
295            }
296        }
297
298        getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
299
300        // see if we should show Back/Next buttons
301        Intent intent = getIntent();
302        if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
303
304            findViewById(com.android.internal.R.id.button_bar).setVisibility(View.VISIBLE);
305
306            Button backButton = (Button)findViewById(com.android.internal.R.id.back_button);
307            backButton.setOnClickListener(new OnClickListener() {
308                public void onClick(View v) {
309                    setResult(RESULT_CANCELED);
310                    finish();
311                }
312            });
313            Button skipButton = (Button)findViewById(com.android.internal.R.id.skip_button);
314            skipButton.setOnClickListener(new OnClickListener() {
315                public void onClick(View v) {
316                    setResult(RESULT_OK);
317                    finish();
318                }
319            });
320            mNextButton = (Button)findViewById(com.android.internal.R.id.next_button);
321            mNextButton.setOnClickListener(new OnClickListener() {
322                public void onClick(View v) {
323                    setResult(RESULT_OK);
324                    finish();
325                }
326            });
327
328            // set our various button parameters
329            if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
330                String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
331                if (TextUtils.isEmpty(buttonText)) {
332                    mNextButton.setVisibility(View.GONE);
333                }
334                else {
335                    mNextButton.setText(buttonText);
336                }
337            }
338            if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
339                String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
340                if (TextUtils.isEmpty(buttonText)) {
341                    backButton.setVisibility(View.GONE);
342                }
343                else {
344                    backButton.setText(buttonText);
345                }
346            }
347            if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
348                skipButton.setVisibility(View.VISIBLE);
349            }
350        }
351    }
352
353    /**
354     * Called to determine if the activity should run in multi-pane mode.
355     * The default implementation returns true if the screen is large
356     * enough.
357     */
358    public boolean onIsMultiPane() {
359        Configuration config = getResources().getConfiguration();
360        if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
361                == Configuration.SCREENLAYOUT_SIZE_XLARGE
362                && config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
363            return true;
364        }
365        return false;
366    }
367
368    /**
369     * Called to determine whether the header list should be hidden.  The
370     * default implementation hides the list if the activity is being re-launched
371     * when not in multi-pane mode.
372     */
373    public boolean onIsHidingHeaders() {
374        return getIntent().getBooleanExtra(EXTRA_PREFS_NO_HEADERS, false);
375    }
376
377    /**
378     * Called to determine the initial fragment to be shown.  The default
379     * implementation simply returns the fragment of the first header.
380     */
381    public String onGetInitialFragment() {
382        return mHeaders.get(0).fragment;
383    }
384
385    /**
386     * Called when the activity needs its list of headers build.  By
387     * implementing this and adding at least one item to the list, you
388     * will cause the activity to run in its modern fragment mode.  Note
389     * that this function may not always be called; for example, if the
390     * activity has been asked to display a particular fragment without
391     * the header list, there is no need to build the headers.
392     *
393     * <p>Typical implementations will use {@link #loadHeadersFromResource}
394     * to fill in the list from a resource.
395     *
396     * @param target The list in which to place the headers.
397     */
398    public void onBuildHeaders(List<Header> target) {
399    }
400
401    /**
402     * Parse the given XML file as a header description, adding each
403     * parsed Header into the target list.
404     *
405     * @param resid The XML resource to load and parse.
406     * @param target The list in which the parsed headers should be placed.
407     */
408    public void loadHeadersFromResource(int resid, List<Header> target) {
409        XmlResourceParser parser = null;
410        try {
411            parser = getResources().getXml(resid);
412            AttributeSet attrs = Xml.asAttributeSet(parser);
413
414            int type;
415            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
416                    && type != XmlPullParser.START_TAG) {
417            }
418
419            String nodeName = parser.getName();
420            if (!"PreferenceHeaders".equals(nodeName)) {
421                throw new RuntimeException(
422                        "XML document must start with <PreferenceHeaders> tag; found"
423                        + nodeName + " at " + parser.getPositionDescription());
424            }
425
426            int outerDepth = parser.getDepth();
427            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
428                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
429                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
430                    continue;
431                }
432
433                nodeName = parser.getName();
434                if ("Header".equals(nodeName)) {
435                    Header header = new Header();
436
437                    TypedArray sa = getResources().obtainAttributes(attrs,
438                            com.android.internal.R.styleable.PreferenceHeader);
439                    header.title = sa.getText(
440                            com.android.internal.R.styleable.PreferenceHeader_title);
441                    header.summary = sa.getText(
442                            com.android.internal.R.styleable.PreferenceHeader_summary);
443                    header.iconRes = sa.getResourceId(
444                            com.android.internal.R.styleable.PreferenceHeader_icon, 0);
445                    header.fragment = sa.getString(
446                            com.android.internal.R.styleable.PreferenceHeader_fragment);
447                    sa.recycle();
448
449                    target.add(header);
450
451                    XmlUtils.skipCurrentTag(parser);
452                } else {
453                    XmlUtils.skipCurrentTag(parser);
454                }
455            }
456
457        } catch (XmlPullParserException e) {
458            throw new RuntimeException("Error parsing headers", e);
459        } catch (IOException e) {
460            throw new RuntimeException("Error parsing headers", e);
461        } finally {
462            if (parser != null) parser.close();
463        }
464
465    }
466
467    @Override
468    protected void onStop() {
469        super.onStop();
470
471        if (mPreferenceManager != null) {
472            mPreferenceManager.dispatchActivityStop();
473        }
474    }
475
476    @Override
477    protected void onDestroy() {
478        super.onDestroy();
479
480        if (mPreferenceManager != null) {
481            mPreferenceManager.dispatchActivityDestroy();
482        }
483    }
484
485    @Override
486    protected void onSaveInstanceState(Bundle outState) {
487        super.onSaveInstanceState(outState);
488
489        if (mPreferenceManager != null) {
490            final PreferenceScreen preferenceScreen = getPreferenceScreen();
491            if (preferenceScreen != null) {
492                Bundle container = new Bundle();
493                preferenceScreen.saveHierarchyState(container);
494                outState.putBundle(PREFERENCES_TAG, container);
495            }
496        }
497    }
498
499    @Override
500    protected void onRestoreInstanceState(Bundle state) {
501        if (mPreferenceManager != null) {
502            Bundle container = state.getBundle(PREFERENCES_TAG);
503            if (container != null) {
504                final PreferenceScreen preferenceScreen = getPreferenceScreen();
505                if (preferenceScreen != null) {
506                    preferenceScreen.restoreHierarchyState(container);
507                    mSavedInstanceState = state;
508                    return;
509                }
510            }
511        }
512
513        // Only call this if we didn't save the instance state for later.
514        // If we did save it, it will be restored when we bind the adapter.
515        super.onRestoreInstanceState(state);
516    }
517
518    @Override
519    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
520        super.onActivityResult(requestCode, resultCode, data);
521
522        if (mPreferenceManager != null) {
523            mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
524        }
525    }
526
527    @Override
528    public void onContentChanged() {
529        super.onContentChanged();
530
531        if (mPreferenceManager != null) {
532            postBindPreferences();
533        }
534    }
535
536    @Override
537    protected void onListItemClick(ListView l, View v, int position, long id) {
538        super.onListItemClick(l, v, position, id);
539
540        if (mAdapter != null) {
541            onHeaderClick(mHeaders.get(position), position);
542        }
543    }
544
545    /**
546     * Called when the user selects an item in the header list.  The default
547     * implementation will call either {@link #startWithFragment(String)}
548     * or {@link #switchToHeader(String)} as appropriate.
549     *
550     * @param header The header that was selected.
551     * @param position The header's position in the list.
552     */
553    public void onHeaderClick(Header header, int position) {
554        if (mSinglePane) {
555            startWithFragment(header.fragment);
556        } else {
557            switchToHeader(header.fragment);
558        }
559    }
560
561    /**
562     * Start a new instance of this activity, showing only the given
563     * preference fragment.  When launched in this mode, the header list
564     * will be hidden and the given preference fragment will be instantiated
565     * and fill the entire activity.
566     *
567     * @param fragmentName The name of the fragment to display.
568     */
569    public void startWithFragment(String fragmentName) {
570        Intent intent = new Intent(Intent.ACTION_MAIN);
571        intent.setClass(this, getClass());
572        intent.putExtra(EXTRA_PREFS_SHOW_FRAGMENT, fragmentName);
573        intent.putExtra(EXTRA_PREFS_NO_HEADERS, true);
574        startActivity(intent);
575    }
576
577    /**
578     * When in two-pane mode, switch the fragment pane to show the given
579     * preference fragment.
580     *
581     * @param fragmentName The name of the fragment to display.
582     */
583    public void switchToHeader(String fragmentName) {
584        popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
585
586        Fragment f;
587        try {
588            f = Fragment.instantiate(this, fragmentName);
589        } catch (Exception e) {
590            Log.w(TAG, "Failure instantiating fragment " + fragmentName, e);
591            return;
592        }
593        openFragmentTransaction().replace(com.android.internal.R.id.prefs, f).commit();
594    }
595
596    @Override
597    public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
598        Fragment f;
599        try {
600            f = Fragment.instantiate(this, pref.getFragment());
601        } catch (Exception e) {
602            Log.w(TAG, "Failure instantiating fragment " + pref.getFragment(), e);
603            return false;
604        }
605        openFragmentTransaction().replace(com.android.internal.R.id.prefs, f)
606                .addToBackStack(BACK_STACK_PREFS).commit();
607        return true;
608    }
609
610    /**
611     * Posts a message to bind the preferences to the list view.
612     * <p>
613     * Binding late is preferred as any custom preference types created in
614     * {@link #onCreate(Bundle)} are able to have their views recycled.
615     */
616    private void postBindPreferences() {
617        if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
618        mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
619    }
620
621    private void bindPreferences() {
622        final PreferenceScreen preferenceScreen = getPreferenceScreen();
623        if (preferenceScreen != null) {
624            preferenceScreen.bind(getListView());
625            if (mSavedInstanceState != null) {
626                super.onRestoreInstanceState(mSavedInstanceState);
627                mSavedInstanceState = null;
628            }
629        }
630    }
631
632    /**
633     * Returns the {@link PreferenceManager} used by this activity.
634     * @return The {@link PreferenceManager}.
635     *
636     * @deprecated This function is not relevant for a modern fragment-based
637     * PreferenceActivity.
638     */
639    @Deprecated
640    public PreferenceManager getPreferenceManager() {
641        return mPreferenceManager;
642    }
643
644    private void requirePreferenceManager() {
645        if (mPreferenceManager == null) {
646            if (mAdapter == null) {
647                throw new RuntimeException("This should be called after super.onCreate.");
648            }
649            throw new RuntimeException(
650                    "Modern two-pane PreferenceActivity requires use of a PreferenceFragment");
651        }
652    }
653
654    /**
655     * Sets the root of the preference hierarchy that this activity is showing.
656     *
657     * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
658     *
659     * @deprecated This function is not relevant for a modern fragment-based
660     * PreferenceActivity.
661     */
662    @Deprecated
663    public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
664        requirePreferenceManager();
665
666        if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
667            postBindPreferences();
668            CharSequence title = getPreferenceScreen().getTitle();
669            // Set the title of the activity
670            if (title != null) {
671                setTitle(title);
672            }
673        }
674    }
675
676    /**
677     * Gets the root of the preference hierarchy that this activity is showing.
678     *
679     * @return The {@link PreferenceScreen} that is the root of the preference
680     *         hierarchy.
681     *
682     * @deprecated This function is not relevant for a modern fragment-based
683     * PreferenceActivity.
684     */
685    @Deprecated
686    public PreferenceScreen getPreferenceScreen() {
687        if (mPreferenceManager != null) {
688            return mPreferenceManager.getPreferenceScreen();
689        }
690        return null;
691    }
692
693    /**
694     * Adds preferences from activities that match the given {@link Intent}.
695     *
696     * @param intent The {@link Intent} to query activities.
697     *
698     * @deprecated This function is not relevant for a modern fragment-based
699     * PreferenceActivity.
700     */
701    @Deprecated
702    public void addPreferencesFromIntent(Intent intent) {
703        requirePreferenceManager();
704
705        setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
706    }
707
708    /**
709     * Inflates the given XML resource and adds the preference hierarchy to the current
710     * preference hierarchy.
711     *
712     * @param preferencesResId The XML resource ID to inflate.
713     *
714     * @deprecated This function is not relevant for a modern fragment-based
715     * PreferenceActivity.
716     */
717    @Deprecated
718    public void addPreferencesFromResource(int preferencesResId) {
719        requirePreferenceManager();
720
721        setPreferenceScreen(mPreferenceManager.inflateFromResource(this, preferencesResId,
722                getPreferenceScreen()));
723    }
724
725    /**
726     * {@inheritDoc}
727     *
728     * @deprecated This function is not relevant for a modern fragment-based
729     * PreferenceActivity.
730     */
731    @Deprecated
732    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
733        return false;
734    }
735
736    /**
737     * Finds a {@link Preference} based on its key.
738     *
739     * @param key The key of the preference to retrieve.
740     * @return The {@link Preference} with the key, or null.
741     * @see PreferenceGroup#findPreference(CharSequence)
742     *
743     * @deprecated This function is not relevant for a modern fragment-based
744     * PreferenceActivity.
745     */
746    @Deprecated
747    public Preference findPreference(CharSequence key) {
748
749        if (mPreferenceManager == null) {
750            return null;
751        }
752
753        return mPreferenceManager.findPreference(key);
754    }
755
756    @Override
757    protected void onNewIntent(Intent intent) {
758        if (mPreferenceManager != null) {
759            mPreferenceManager.dispatchNewIntent(intent);
760        }
761    }
762
763    // give subclasses access to the Next button
764    /** @hide */
765    protected boolean hasNextButton() {
766        return mNextButton != null;
767    }
768    /** @hide */
769    protected Button getNextButton() {
770        return mNextButton;
771    }
772}
773