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     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