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