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