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 android.app.Activity;
20import android.content.Context;
21import android.content.DialogInterface;
22import android.content.Intent;
23import android.content.SharedPreferences;
24import android.content.pm.ActivityInfo;
25import android.content.pm.PackageManager;
26import android.content.pm.ResolveInfo;
27import android.content.pm.PackageManager.NameNotFoundException;
28import android.content.res.XmlResourceParser;
29import android.os.Bundle;
30import android.util.Log;
31
32import java.util.ArrayList;
33import java.util.HashSet;
34import java.util.List;
35
36/**
37 * Used to help create {@link Preference} hierarchies
38 * from activities or XML.
39 * <p>
40 * In most cases, clients should use
41 * {@link PreferenceActivity#addPreferencesFromIntent} or
42 * {@link PreferenceActivity#addPreferencesFromResource(int)}.
43 *
44 * @see PreferenceActivity
45 */
46public class PreferenceManager {
47
48    private static final String TAG = "PreferenceManager";
49
50    /**
51     * The Activity meta-data key for its XML preference hierarchy.
52     */
53    public static final String METADATA_KEY_PREFERENCES = "android.preference";
54
55    public static final String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
56
57    /**
58     * @see #getActivity()
59     */
60    private Activity mActivity;
61
62    /**
63     * Fragment that owns this instance.
64     */
65    private PreferenceFragment mFragment;
66
67    /**
68     * The context to use. This should always be set.
69     *
70     * @see #mActivity
71     */
72    private Context mContext;
73
74    /**
75     * The counter for unique IDs.
76     */
77    private long mNextId = 0;
78
79    /**
80     * The counter for unique request codes.
81     */
82    private int mNextRequestCode;
83
84    /**
85     * Cached shared preferences.
86     */
87    private SharedPreferences mSharedPreferences;
88
89    /**
90     * If in no-commit mode, the shared editor to give out (which will be
91     * committed when exiting no-commit mode).
92     */
93    private SharedPreferences.Editor mEditor;
94
95    /**
96     * Blocks commits from happening on the shared editor. This is used when
97     * inflating the hierarchy. Do not set this directly, use {@link #setNoCommit(boolean)}
98     */
99    private boolean mNoCommit;
100
101    /**
102     * The SharedPreferences name that will be used for all {@link Preference}s
103     * managed by this instance.
104     */
105    private String mSharedPreferencesName;
106
107    /**
108     * The SharedPreferences mode that will be used for all {@link Preference}s
109     * managed by this instance.
110     */
111    private int mSharedPreferencesMode;
112
113    /**
114     * The {@link PreferenceScreen} at the root of the preference hierarchy.
115     */
116    private PreferenceScreen mPreferenceScreen;
117
118    /**
119     * List of activity result listeners.
120     */
121    private List<OnActivityResultListener> mActivityResultListeners;
122
123    /**
124     * List of activity stop listeners.
125     */
126    private List<OnActivityStopListener> mActivityStopListeners;
127
128    /**
129     * List of activity destroy listeners.
130     */
131    private List<OnActivityDestroyListener> mActivityDestroyListeners;
132
133    /**
134     * List of dialogs that should be dismissed when we receive onNewIntent in
135     * our PreferenceActivity.
136     */
137    private List<DialogInterface> mPreferencesScreens;
138
139    private OnPreferenceTreeClickListener mOnPreferenceTreeClickListener;
140
141    PreferenceManager(Activity activity, int firstRequestCode) {
142        mActivity = activity;
143        mNextRequestCode = firstRequestCode;
144
145        init(activity);
146    }
147
148    /**
149     * This constructor should ONLY be used when getting default values from
150     * an XML preference hierarchy.
151     * <p>
152     * The {@link PreferenceManager#PreferenceManager(Activity)}
153     * should be used ANY time a preference will be displayed, since some preference
154     * types need an Activity for managed queries.
155     */
156    private PreferenceManager(Context context) {
157        init(context);
158    }
159
160    private void init(Context context) {
161        mContext = context;
162
163        setSharedPreferencesName(getDefaultSharedPreferencesName(context));
164    }
165
166    /**
167     * Sets the owning preference fragment
168     */
169    void setFragment(PreferenceFragment fragment) {
170        mFragment = fragment;
171    }
172
173    /**
174     * Returns the owning preference fragment, if any.
175     */
176    PreferenceFragment getFragment() {
177        return mFragment;
178    }
179
180    /**
181     * Returns a list of {@link Activity} (indirectly) that match a given
182     * {@link Intent}.
183     *
184     * @param queryIntent The Intent to match.
185     * @return The list of {@link ResolveInfo} that point to the matched
186     *         activities.
187     */
188    private List<ResolveInfo> queryIntentActivities(Intent queryIntent) {
189        return mContext.getPackageManager().queryIntentActivities(queryIntent,
190                PackageManager.GET_META_DATA);
191    }
192
193    /**
194     * Inflates a preference hierarchy from the preference hierarchies of
195     * {@link Activity Activities} that match the given {@link Intent}. An
196     * {@link Activity} defines its preference hierarchy with meta-data using
197     * the {@link #METADATA_KEY_PREFERENCES} key.
198     * <p>
199     * If a preference hierarchy is given, the new preference hierarchies will
200     * be merged in.
201     *
202     * @param queryIntent The intent to match activities.
203     * @param rootPreferences Optional existing hierarchy to merge the new
204     *            hierarchies into.
205     * @return The root hierarchy (if one was not provided, the new hierarchy's
206     *         root).
207     */
208    PreferenceScreen inflateFromIntent(Intent queryIntent, PreferenceScreen rootPreferences) {
209        final List<ResolveInfo> activities = queryIntentActivities(queryIntent);
210        final HashSet<String> inflatedRes = new HashSet<String>();
211
212        for (int i = activities.size() - 1; i >= 0; i--) {
213            final ActivityInfo activityInfo = activities.get(i).activityInfo;
214            final Bundle metaData = activityInfo.metaData;
215
216            if ((metaData == null) || !metaData.containsKey(METADATA_KEY_PREFERENCES)) {
217                continue;
218            }
219
220            // Need to concat the package with res ID since the same res ID
221            // can be re-used across contexts
222            final String uniqueResId = activityInfo.packageName + ":"
223                    + activityInfo.metaData.getInt(METADATA_KEY_PREFERENCES);
224
225            if (!inflatedRes.contains(uniqueResId)) {
226                inflatedRes.add(uniqueResId);
227
228                final Context context;
229                try {
230                    context = mContext.createPackageContext(activityInfo.packageName, 0);
231                } catch (NameNotFoundException e) {
232                    Log.w(TAG, "Could not create context for " + activityInfo.packageName + ": "
233                        + Log.getStackTraceString(e));
234                    continue;
235                }
236
237                final PreferenceInflater inflater = new PreferenceInflater(context, this);
238                final XmlResourceParser parser = activityInfo.loadXmlMetaData(context
239                        .getPackageManager(), METADATA_KEY_PREFERENCES);
240                rootPreferences = (PreferenceScreen) inflater
241                        .inflate(parser, rootPreferences, true);
242                parser.close();
243            }
244        }
245
246        rootPreferences.onAttachedToHierarchy(this);
247
248        return rootPreferences;
249    }
250
251    /**
252     * Inflates a preference hierarchy from XML. If a preference hierarchy is
253     * given, the new preference hierarchies will be merged in.
254     *
255     * @param context The context of the resource.
256     * @param resId The resource ID of the XML to inflate.
257     * @param rootPreferences Optional existing hierarchy to merge the new
258     *            hierarchies into.
259     * @return The root hierarchy (if one was not provided, the new hierarchy's
260     *         root).
261     * @hide
262     */
263    public PreferenceScreen inflateFromResource(Context context, int resId,
264            PreferenceScreen rootPreferences) {
265        // Block commits
266        setNoCommit(true);
267
268        final PreferenceInflater inflater = new PreferenceInflater(context, this);
269        rootPreferences = (PreferenceScreen) inflater.inflate(resId, rootPreferences, true);
270        rootPreferences.onAttachedToHierarchy(this);
271
272        // Unblock commits
273        setNoCommit(false);
274
275        return rootPreferences;
276    }
277
278    public PreferenceScreen createPreferenceScreen(Context context) {
279        final PreferenceScreen preferenceScreen = new PreferenceScreen(context, null);
280        preferenceScreen.onAttachedToHierarchy(this);
281        return preferenceScreen;
282    }
283
284    /**
285     * Called by a preference to get a unique ID in its hierarchy.
286     *
287     * @return A unique ID.
288     */
289    long getNextId() {
290        synchronized (this) {
291            return mNextId++;
292        }
293    }
294
295    /**
296     * Returns the current name of the SharedPreferences file that preferences managed by
297     * this will use.
298     *
299     * @return The name that can be passed to {@link Context#getSharedPreferences(String, int)}.
300     * @see Context#getSharedPreferences(String, int)
301     */
302    public String getSharedPreferencesName() {
303        return mSharedPreferencesName;
304    }
305
306    /**
307     * Sets the name of the SharedPreferences file that preferences managed by this
308     * will use.
309     *
310     * @param sharedPreferencesName The name of the SharedPreferences file.
311     * @see Context#getSharedPreferences(String, int)
312     */
313    public void setSharedPreferencesName(String sharedPreferencesName) {
314        mSharedPreferencesName = sharedPreferencesName;
315        mSharedPreferences = null;
316    }
317
318    /**
319     * Returns the current mode of the SharedPreferences file that preferences managed by
320     * this will use.
321     *
322     * @return The mode that can be passed to {@link Context#getSharedPreferences(String, int)}.
323     * @see Context#getSharedPreferences(String, int)
324     */
325    public int getSharedPreferencesMode() {
326        return mSharedPreferencesMode;
327    }
328
329    /**
330     * Sets the mode of the SharedPreferences file that preferences managed by this
331     * will use.
332     *
333     * @param sharedPreferencesMode The mode of the SharedPreferences file.
334     * @see Context#getSharedPreferences(String, int)
335     */
336    public void setSharedPreferencesMode(int sharedPreferencesMode) {
337        mSharedPreferencesMode = sharedPreferencesMode;
338        mSharedPreferences = null;
339    }
340
341    /**
342     * Gets a SharedPreferences instance that preferences managed by this will
343     * use.
344     *
345     * @return A SharedPreferences instance pointing to the file that contains
346     *         the values of preferences that are managed by this.
347     */
348    public SharedPreferences getSharedPreferences() {
349        if (mSharedPreferences == null) {
350            mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
351                    mSharedPreferencesMode);
352        }
353
354        return mSharedPreferences;
355    }
356
357    /**
358     * Gets a SharedPreferences instance that points to the default file that is
359     * used by the preference framework in the given context.
360     *
361     * @param context The context of the preferences whose values are wanted.
362     * @return A SharedPreferences instance that can be used to retrieve and
363     *         listen to values of the preferences.
364     */
365    public static SharedPreferences getDefaultSharedPreferences(Context context) {
366        return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
367                getDefaultSharedPreferencesMode());
368    }
369
370    private static String getDefaultSharedPreferencesName(Context context) {
371        return context.getPackageName() + "_preferences";
372    }
373
374    private static int getDefaultSharedPreferencesMode() {
375        return Context.MODE_PRIVATE;
376    }
377
378    /**
379     * Returns the root of the preference hierarchy managed by this class.
380     *
381     * @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
382     */
383    PreferenceScreen getPreferenceScreen() {
384        return mPreferenceScreen;
385    }
386
387    /**
388     * Sets the root of the preference hierarchy.
389     *
390     * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
391     * @return Whether the {@link PreferenceScreen} given is different than the previous.
392     */
393    boolean setPreferences(PreferenceScreen preferenceScreen) {
394        if (preferenceScreen != mPreferenceScreen) {
395            mPreferenceScreen = preferenceScreen;
396            return true;
397        }
398
399        return false;
400    }
401
402    /**
403     * Finds a {@link Preference} based on its key.
404     *
405     * @param key The key of the preference to retrieve.
406     * @return The {@link Preference} with the key, or null.
407     * @see PreferenceGroup#findPreference(CharSequence)
408     */
409    public Preference findPreference(CharSequence key) {
410        if (mPreferenceScreen == null) {
411            return null;
412        }
413
414        return mPreferenceScreen.findPreference(key);
415    }
416
417    /**
418     * Sets the default values from an XML preference file by reading the values defined
419     * by each {@link Preference} item's {@code android:defaultValue} attribute. This should
420     * be called by the application's main activity.
421     * <p>
422     *
423     * @param context The context of the shared preferences.
424     * @param resId The resource ID of the preference XML file.
425     * @param readAgain Whether to re-read the default values.
426     * If false, this method sets the default values only if this
427     * method has never been called in the past (or if the
428     * {@link #KEY_HAS_SET_DEFAULT_VALUES} in the default value shared
429     * preferences file is false). To attempt to set the default values again
430     * bypassing this check, set {@code readAgain} to true.
431     *            <p class="note">
432     *            Note: this will NOT reset preferences back to their default
433     *            values. For that functionality, use
434     *            {@link PreferenceManager#getDefaultSharedPreferences(Context)}
435     *            and clear it followed by a call to this method with this
436     *            parameter set to true.
437     */
438    public static void setDefaultValues(Context context, int resId, boolean readAgain) {
439
440        // Use the default shared preferences name and mode
441        setDefaultValues(context, getDefaultSharedPreferencesName(context),
442                getDefaultSharedPreferencesMode(), resId, readAgain);
443    }
444
445    /**
446     * Similar to {@link #setDefaultValues(Context, int, boolean)} but allows
447     * the client to provide the filename and mode of the shared preferences
448     * file.
449     *
450     * @param context The context of the shared preferences.
451     * @param sharedPreferencesName A custom name for the shared preferences file.
452     * @param sharedPreferencesMode The file creation mode for the shared preferences file, such
453     * as {@link android.content.Context#MODE_PRIVATE} or {@link
454     * android.content.Context#MODE_PRIVATE}
455     * @param resId The resource ID of the preference XML file.
456     * @param readAgain Whether to re-read the default values.
457     * If false, this method will set the default values only if this
458     * method has never been called in the past (or if the
459     * {@link #KEY_HAS_SET_DEFAULT_VALUES} in the default value shared
460     * preferences file is false). To attempt to set the default values again
461     * bypassing this check, set {@code readAgain} to true.
462     *            <p class="note">
463     *            Note: this will NOT reset preferences back to their default
464     *            values. For that functionality, use
465     *            {@link PreferenceManager#getDefaultSharedPreferences(Context)}
466     *            and clear it followed by a call to this method with this
467     *            parameter set to true.
468     *
469     * @see #setDefaultValues(Context, int, boolean)
470     * @see #setSharedPreferencesName(String)
471     * @see #setSharedPreferencesMode(int)
472     */
473    public static void setDefaultValues(Context context, String sharedPreferencesName,
474            int sharedPreferencesMode, int resId, boolean readAgain) {
475        final SharedPreferences defaultValueSp = context.getSharedPreferences(
476                KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE);
477
478        if (readAgain || !defaultValueSp.getBoolean(KEY_HAS_SET_DEFAULT_VALUES, false)) {
479            final PreferenceManager pm = new PreferenceManager(context);
480            pm.setSharedPreferencesName(sharedPreferencesName);
481            pm.setSharedPreferencesMode(sharedPreferencesMode);
482            pm.inflateFromResource(context, resId, null);
483
484            SharedPreferences.Editor editor =
485                    defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true);
486            try {
487                editor.apply();
488            } catch (AbstractMethodError unused) {
489                // The app injected its own pre-Gingerbread
490                // SharedPreferences.Editor implementation without
491                // an apply method.
492                editor.commit();
493            }
494        }
495    }
496
497    /**
498     * Returns an editor to use when modifying the shared preferences.
499     * <p>
500     * Do NOT commit unless {@link #shouldCommit()} returns true.
501     *
502     * @return An editor to use to write to shared preferences.
503     * @see #shouldCommit()
504     */
505    SharedPreferences.Editor getEditor() {
506
507        if (mNoCommit) {
508            if (mEditor == null) {
509                mEditor = getSharedPreferences().edit();
510            }
511
512            return mEditor;
513        } else {
514            return getSharedPreferences().edit();
515        }
516    }
517
518    /**
519     * Whether it is the client's responsibility to commit on the
520     * {@link #getEditor()}. This will return false in cases where the writes
521     * should be batched, for example when inflating preferences from XML.
522     *
523     * @return Whether the client should commit.
524     */
525    boolean shouldCommit() {
526        return !mNoCommit;
527    }
528
529    private void setNoCommit(boolean noCommit) {
530        if (!noCommit && mEditor != null) {
531            try {
532                mEditor.apply();
533            } catch (AbstractMethodError unused) {
534                // The app injected its own pre-Gingerbread
535                // SharedPreferences.Editor implementation without
536                // an apply method.
537                mEditor.commit();
538            }
539        }
540        mNoCommit = noCommit;
541    }
542
543    /**
544     * Returns the activity that shows the preferences. This is useful for doing
545     * managed queries, but in most cases the use of {@link #getContext()} is
546     * preferred.
547     * <p>
548     * This will return null if this class was instantiated with a Context
549     * instead of Activity. For example, when setting the default values.
550     *
551     * @return The activity that shows the preferences.
552     * @see #mContext
553     */
554    Activity getActivity() {
555        return mActivity;
556    }
557
558    /**
559     * Returns the context. This is preferred over {@link #getActivity()} when
560     * possible.
561     *
562     * @return The context.
563     */
564    Context getContext() {
565        return mContext;
566    }
567
568    /**
569     * Registers a listener.
570     *
571     * @see OnActivityResultListener
572     */
573    void registerOnActivityResultListener(OnActivityResultListener listener) {
574        synchronized (this) {
575            if (mActivityResultListeners == null) {
576                mActivityResultListeners = new ArrayList<OnActivityResultListener>();
577            }
578
579            if (!mActivityResultListeners.contains(listener)) {
580                mActivityResultListeners.add(listener);
581            }
582        }
583    }
584
585    /**
586     * Unregisters a listener.
587     *
588     * @see OnActivityResultListener
589     */
590    void unregisterOnActivityResultListener(OnActivityResultListener listener) {
591        synchronized (this) {
592            if (mActivityResultListeners != null) {
593                mActivityResultListeners.remove(listener);
594            }
595        }
596    }
597
598    /**
599     * Called by the {@link PreferenceManager} to dispatch a subactivity result.
600     */
601    void dispatchActivityResult(int requestCode, int resultCode, Intent data) {
602        List<OnActivityResultListener> list;
603
604        synchronized (this) {
605            if (mActivityResultListeners == null) return;
606            list = new ArrayList<OnActivityResultListener>(mActivityResultListeners);
607        }
608
609        final int N = list.size();
610        for (int i = 0; i < N; i++) {
611            if (list.get(i).onActivityResult(requestCode, resultCode, data)) {
612                break;
613            }
614        }
615    }
616
617    /**
618     * Registers a listener.
619     *
620     * @see OnActivityStopListener
621     */
622    void registerOnActivityStopListener(OnActivityStopListener listener) {
623        synchronized (this) {
624            if (mActivityStopListeners == null) {
625                mActivityStopListeners = new ArrayList<OnActivityStopListener>();
626            }
627
628            if (!mActivityStopListeners.contains(listener)) {
629                mActivityStopListeners.add(listener);
630            }
631        }
632    }
633
634    /**
635     * Unregisters a listener.
636     *
637     * @see OnActivityStopListener
638     */
639    void unregisterOnActivityStopListener(OnActivityStopListener listener) {
640        synchronized (this) {
641            if (mActivityStopListeners != null) {
642                mActivityStopListeners.remove(listener);
643            }
644        }
645    }
646
647    /**
648     * Called by the {@link PreferenceManager} to dispatch the activity stop
649     * event.
650     */
651    void dispatchActivityStop() {
652        List<OnActivityStopListener> list;
653
654        synchronized (this) {
655            if (mActivityStopListeners == null) return;
656            list = new ArrayList<OnActivityStopListener>(mActivityStopListeners);
657        }
658
659        final int N = list.size();
660        for (int i = 0; i < N; i++) {
661            list.get(i).onActivityStop();
662        }
663    }
664
665    /**
666     * Registers a listener.
667     *
668     * @see OnActivityDestroyListener
669     */
670    void registerOnActivityDestroyListener(OnActivityDestroyListener listener) {
671        synchronized (this) {
672            if (mActivityDestroyListeners == null) {
673                mActivityDestroyListeners = new ArrayList<OnActivityDestroyListener>();
674            }
675
676            if (!mActivityDestroyListeners.contains(listener)) {
677                mActivityDestroyListeners.add(listener);
678            }
679        }
680    }
681
682    /**
683     * Unregisters a listener.
684     *
685     * @see OnActivityDestroyListener
686     */
687    void unregisterOnActivityDestroyListener(OnActivityDestroyListener listener) {
688        synchronized (this) {
689            if (mActivityDestroyListeners != null) {
690                mActivityDestroyListeners.remove(listener);
691            }
692        }
693    }
694
695    /**
696     * Called by the {@link PreferenceManager} to dispatch the activity destroy
697     * event.
698     */
699    void dispatchActivityDestroy() {
700        List<OnActivityDestroyListener> list = null;
701
702        synchronized (this) {
703            if (mActivityDestroyListeners != null) {
704                list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
705            }
706        }
707
708        if (list != null) {
709            final int N = list.size();
710            for (int i = 0; i < N; i++) {
711                list.get(i).onActivityDestroy();
712            }
713        }
714
715        // Dismiss any PreferenceScreens still showing
716        dismissAllScreens();
717    }
718
719    /**
720     * Returns a request code that is unique for the activity. Each subsequent
721     * call to this method should return another unique request code.
722     *
723     * @return A unique request code that will never be used by anyone other
724     *         than the caller of this method.
725     */
726    int getNextRequestCode() {
727        synchronized (this) {
728            return mNextRequestCode++;
729        }
730    }
731
732    void addPreferencesScreen(DialogInterface screen) {
733        synchronized (this) {
734
735            if (mPreferencesScreens == null) {
736                mPreferencesScreens = new ArrayList<DialogInterface>();
737            }
738
739            mPreferencesScreens.add(screen);
740        }
741    }
742
743    void removePreferencesScreen(DialogInterface screen) {
744        synchronized (this) {
745
746            if (mPreferencesScreens == null) {
747                return;
748            }
749
750            mPreferencesScreens.remove(screen);
751        }
752    }
753
754    /**
755     * Called by {@link PreferenceActivity} to dispatch the new Intent event.
756     *
757     * @param intent The new Intent.
758     */
759    void dispatchNewIntent(Intent intent) {
760        dismissAllScreens();
761    }
762
763    private void dismissAllScreens() {
764        // Remove any of the previously shown preferences screens
765        ArrayList<DialogInterface> screensToDismiss;
766
767        synchronized (this) {
768
769            if (mPreferencesScreens == null) {
770                return;
771            }
772
773            screensToDismiss = new ArrayList<DialogInterface>(mPreferencesScreens);
774            mPreferencesScreens.clear();
775        }
776
777        for (int i = screensToDismiss.size() - 1; i >= 0; i--) {
778            screensToDismiss.get(i).dismiss();
779        }
780    }
781
782    /**
783     * Sets the callback to be invoked when a {@link Preference} in the
784     * hierarchy rooted at this {@link PreferenceManager} is clicked.
785     *
786     * @param listener The callback to be invoked.
787     */
788    void setOnPreferenceTreeClickListener(OnPreferenceTreeClickListener listener) {
789        mOnPreferenceTreeClickListener = listener;
790    }
791
792    OnPreferenceTreeClickListener getOnPreferenceTreeClickListener() {
793        return mOnPreferenceTreeClickListener;
794    }
795
796    /**
797     * Interface definition for a callback to be invoked when a
798     * {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
799     * clicked.
800     */
801    interface OnPreferenceTreeClickListener {
802        /**
803         * Called when a preference in the tree rooted at this
804         * {@link PreferenceScreen} has been clicked.
805         *
806         * @param preferenceScreen The {@link PreferenceScreen} that the
807         *        preference is located in.
808         * @param preference The preference that was clicked.
809         * @return Whether the click was handled.
810         */
811        boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference);
812    }
813
814    /**
815     * Interface definition for a class that will be called when the container's activity
816     * receives an activity result.
817     */
818    public interface OnActivityResultListener {
819
820        /**
821         * See Activity's onActivityResult.
822         *
823         * @return Whether the request code was handled (in which case
824         *         subsequent listeners will not be called.
825         */
826        boolean onActivityResult(int requestCode, int resultCode, Intent data);
827    }
828
829    /**
830     * Interface definition for a class that will be called when the container's activity
831     * is stopped.
832     */
833    public interface OnActivityStopListener {
834
835        /**
836         * See Activity's onStop.
837         */
838        void onActivityStop();
839    }
840
841    /**
842     * Interface definition for a class that will be called when the container's activity
843     * is destroyed.
844     */
845    public interface OnActivityDestroyListener {
846
847        /**
848         * See Activity's onDestroy.
849         */
850        void onActivityDestroy();
851    }
852
853}
854