• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.support.v7.preference;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.support.v4.content.SharedPreferencesCompat;
22 
23 /**
24  * Used to help create {@link Preference} hierarchies
25  * from activities or XML.
26  * <p>
27  * In most cases, clients should use
28  * {@link android.support.v14.preference.PreferenceFragment#addPreferencesFromResource(int)}, or
29  * {@link PreferenceFragmentCompat#addPreferencesFromResource(int)}.
30  *
31  * @see android.support.v14.preference.PreferenceFragment
32  * @see PreferenceFragmentCompat
33  */
34 public class PreferenceManager {
35 
36     private static final String TAG = "PreferenceManager";
37 
38     public static final String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
39 
40     /**
41      * The context to use. This should always be set.
42      */
43     private Context mContext;
44 
45     /**
46      * The counter for unique IDs.
47      */
48     private long mNextId = 0;
49 
50     /**
51      * Cached shared preferences.
52      */
53     private SharedPreferences mSharedPreferences;
54 
55     /**
56      * If in no-commit mode, the shared editor to give out (which will be
57      * committed when exiting no-commit mode).
58      */
59     private SharedPreferences.Editor mEditor;
60 
61     /**
62      * Blocks commits from happening on the shared editor. This is used when
63      * inflating the hierarchy. Do not set this directly, use {@link #setNoCommit(boolean)}
64      */
65     private boolean mNoCommit;
66 
67     /**
68      * The SharedPreferences name that will be used for all {@link Preference}s
69      * managed by this instance.
70      */
71     private String mSharedPreferencesName;
72 
73     /**
74      * The SharedPreferences mode that will be used for all {@link Preference}s
75      * managed by this instance.
76      */
77     private int mSharedPreferencesMode;
78 
79     /**
80      * The {@link PreferenceScreen} at the root of the preference hierarchy.
81      */
82     private PreferenceScreen mPreferenceScreen;
83 
84     private OnPreferenceTreeClickListener mOnPreferenceTreeClickListener;
85     private OnDisplayPreferenceDialogListener mOnDisplayPreferenceDialogListener;
86     private OnNavigateToScreenListener mOnNavigateToScreenListener;
87 
88     /**
89      * @hide
90      */
PreferenceManager(Context context)91     public PreferenceManager(Context context) {
92         mContext = context;
93 
94         setSharedPreferencesName(getDefaultSharedPreferencesName(context));
95     }
96 
97     /**
98      * Inflates a preference hierarchy from XML. If a preference hierarchy is
99      * given, the new preference hierarchies will be merged in.
100      *
101      * @param context The context of the resource.
102      * @param resId The resource ID of the XML to inflate.
103      * @param rootPreferences Optional existing hierarchy to merge the new
104      *            hierarchies into.
105      * @return The root hierarchy (if one was not provided, the new hierarchy's
106      *         root).
107      * @hide
108      */
inflateFromResource(Context context, int resId, PreferenceScreen rootPreferences)109     public PreferenceScreen inflateFromResource(Context context, int resId,
110             PreferenceScreen rootPreferences) {
111         // Block commits
112         setNoCommit(true);
113 
114         final PreferenceInflater inflater = new PreferenceInflater(context, this);
115         rootPreferences = (PreferenceScreen) inflater.inflate(resId, rootPreferences);
116         rootPreferences.onAttachedToHierarchy(this);
117 
118         // Unblock commits
119         setNoCommit(false);
120 
121         return rootPreferences;
122     }
123 
createPreferenceScreen(Context context)124     public PreferenceScreen createPreferenceScreen(Context context) {
125         final PreferenceScreen preferenceScreen = new PreferenceScreen(context, null);
126         preferenceScreen.onAttachedToHierarchy(this);
127         return preferenceScreen;
128     }
129 
130     /**
131      * Called by a preference to get a unique ID in its hierarchy.
132      *
133      * @return A unique ID.
134      */
getNextId()135     long getNextId() {
136         synchronized (this) {
137             return mNextId++;
138         }
139     }
140 
141     /**
142      * Returns the current name of the SharedPreferences file that preferences managed by
143      * this will use.
144      *
145      * @return The name that can be passed to {@link Context#getSharedPreferences(String, int)}.
146      * @see Context#getSharedPreferences(String, int)
147      */
getSharedPreferencesName()148     public String getSharedPreferencesName() {
149         return mSharedPreferencesName;
150     }
151 
152     /**
153      * Sets the name of the SharedPreferences file that preferences managed by this
154      * will use.
155      *
156      * @param sharedPreferencesName The name of the SharedPreferences file.
157      * @see Context#getSharedPreferences(String, int)
158      */
setSharedPreferencesName(String sharedPreferencesName)159     public void setSharedPreferencesName(String sharedPreferencesName) {
160         mSharedPreferencesName = sharedPreferencesName;
161         mSharedPreferences = null;
162     }
163 
164     /**
165      * Returns the current mode of the SharedPreferences file that preferences managed by
166      * this will use.
167      *
168      * @return The mode that can be passed to {@link Context#getSharedPreferences(String, int)}.
169      * @see Context#getSharedPreferences(String, int)
170      */
getSharedPreferencesMode()171     public int getSharedPreferencesMode() {
172         return mSharedPreferencesMode;
173     }
174 
175     /**
176      * Sets the mode of the SharedPreferences file that preferences managed by this
177      * will use.
178      *
179      * @param sharedPreferencesMode The mode of the SharedPreferences file.
180      * @see Context#getSharedPreferences(String, int)
181      */
setSharedPreferencesMode(int sharedPreferencesMode)182     public void setSharedPreferencesMode(int sharedPreferencesMode) {
183         mSharedPreferencesMode = sharedPreferencesMode;
184         mSharedPreferences = null;
185     }
186 
187     /**
188      * Gets a SharedPreferences instance that preferences managed by this will
189      * use.
190      *
191      * @return A SharedPreferences instance pointing to the file that contains
192      *         the values of preferences that are managed by this.
193      */
getSharedPreferences()194     public SharedPreferences getSharedPreferences() {
195         if (mSharedPreferences == null) {
196             mSharedPreferences = mContext.getSharedPreferences(mSharedPreferencesName,
197                     mSharedPreferencesMode);
198         }
199 
200         return mSharedPreferences;
201     }
202 
203     /**
204      * Gets a SharedPreferences instance that points to the default file that is
205      * used by the preference framework in the given context.
206      *
207      * @param context The context of the preferences whose values are wanted.
208      * @return A SharedPreferences instance that can be used to retrieve and
209      *         listen to values of the preferences.
210      */
getDefaultSharedPreferences(Context context)211     public static SharedPreferences getDefaultSharedPreferences(Context context) {
212         return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
213                 getDefaultSharedPreferencesMode());
214     }
215 
getDefaultSharedPreferencesName(Context context)216     private static String getDefaultSharedPreferencesName(Context context) {
217         return context.getPackageName() + "_preferences";
218     }
219 
getDefaultSharedPreferencesMode()220     private static int getDefaultSharedPreferencesMode() {
221         return Context.MODE_PRIVATE;
222     }
223 
224     /**
225      * Returns the root of the preference hierarchy managed by this class.
226      *
227      * @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
228      */
getPreferenceScreen()229     public PreferenceScreen getPreferenceScreen() {
230         return mPreferenceScreen;
231     }
232 
233     /**
234      * Sets the root of the preference hierarchy.
235      *
236      * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
237      * @return Whether the {@link PreferenceScreen} given is different than the previous.
238      */
setPreferences(PreferenceScreen preferenceScreen)239     public boolean setPreferences(PreferenceScreen preferenceScreen) {
240         if (preferenceScreen != mPreferenceScreen) {
241             mPreferenceScreen = preferenceScreen;
242             return true;
243         }
244 
245         return false;
246     }
247 
248     /**
249      * Finds a {@link Preference} based on its key.
250      *
251      * @param key The key of the preference to retrieve.
252      * @return The {@link Preference} with the key, or null.
253      * @see PreferenceGroup#findPreference(CharSequence)
254      */
findPreference(CharSequence key)255     public Preference findPreference(CharSequence key) {
256         if (mPreferenceScreen == null) {
257             return null;
258         }
259 
260         return mPreferenceScreen.findPreference(key);
261     }
262 
263     /**
264      * Sets the default values from an XML preference file by reading the values defined
265      * by each {@link Preference} item's {@code android:defaultValue} attribute. This should
266      * be called by the application's main activity.
267      * <p>
268      *
269      * @param context The context of the shared preferences.
270      * @param resId The resource ID of the preference XML file.
271      * @param readAgain Whether to re-read the default values.
272      * If false, this method sets the default values only if this
273      * method has never been called in the past (or if the
274      * {@link #KEY_HAS_SET_DEFAULT_VALUES} in the default value shared
275      * preferences file is false). To attempt to set the default values again
276      * bypassing this check, set {@code readAgain} to true.
277      *            <p class="note">
278      *            Note: this will NOT reset preferences back to their default
279      *            values. For that functionality, use
280      *            {@link PreferenceManager#getDefaultSharedPreferences(Context)}
281      *            and clear it followed by a call to this method with this
282      *            parameter set to true.
283      */
setDefaultValues(Context context, int resId, boolean readAgain)284     public static void setDefaultValues(Context context, int resId, boolean readAgain) {
285 
286         // Use the default shared preferences name and mode
287         setDefaultValues(context, getDefaultSharedPreferencesName(context),
288                 getDefaultSharedPreferencesMode(), resId, readAgain);
289     }
290 
291     /**
292      * Similar to {@link #setDefaultValues(Context, int, boolean)} but allows
293      * the client to provide the filename and mode of the shared preferences
294      * file.
295      *
296      * @param context The context of the shared preferences.
297      * @param sharedPreferencesName A custom name for the shared preferences file.
298      * @param sharedPreferencesMode The file creation mode for the shared preferences file, such
299      * as {@link android.content.Context#MODE_PRIVATE} or {@link
300      * android.content.Context#MODE_PRIVATE}
301      * @param resId The resource ID of the preference XML file.
302      * @param readAgain Whether to re-read the default values.
303      * If false, this method will set the default values only if this
304      * method has never been called in the past (or if the
305      * {@link #KEY_HAS_SET_DEFAULT_VALUES} in the default value shared
306      * preferences file is false). To attempt to set the default values again
307      * bypassing this check, set {@code readAgain} to true.
308      *            <p class="note">
309      *            Note: this will NOT reset preferences back to their default
310      *            values. For that functionality, use
311      *            {@link PreferenceManager#getDefaultSharedPreferences(Context)}
312      *            and clear it followed by a call to this method with this
313      *            parameter set to true.
314      *
315      * @see #setDefaultValues(Context, int, boolean)
316      * @see #setSharedPreferencesName(String)
317      * @see #setSharedPreferencesMode(int)
318      */
setDefaultValues(Context context, String sharedPreferencesName, int sharedPreferencesMode, int resId, boolean readAgain)319     public static void setDefaultValues(Context context, String sharedPreferencesName,
320             int sharedPreferencesMode, int resId, boolean readAgain) {
321         final SharedPreferences defaultValueSp = context.getSharedPreferences(
322                 KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE);
323 
324         if (readAgain || !defaultValueSp.getBoolean(KEY_HAS_SET_DEFAULT_VALUES, false)) {
325             final PreferenceManager pm = new PreferenceManager(context);
326             pm.setSharedPreferencesName(sharedPreferencesName);
327             pm.setSharedPreferencesMode(sharedPreferencesMode);
328             pm.inflateFromResource(context, resId, null);
329 
330             SharedPreferences.Editor editor =
331                     defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true);
332 
333             SharedPreferencesCompat.EditorCompat.getInstance().apply(editor);
334         }
335     }
336 
337     /**
338      * Returns an editor to use when modifying the shared preferences.
339      * <p>
340      * Do NOT commit unless {@link #shouldCommit()} returns true.
341      *
342      * @return An editor to use to write to shared preferences.
343      * @see #shouldCommit()
344      */
getEditor()345     SharedPreferences.Editor getEditor() {
346 
347         if (mNoCommit) {
348             if (mEditor == null) {
349                 mEditor = getSharedPreferences().edit();
350             }
351 
352             return mEditor;
353         } else {
354             return getSharedPreferences().edit();
355         }
356     }
357 
358     /**
359      * Whether it is the client's responsibility to commit on the
360      * {@link #getEditor()}. This will return false in cases where the writes
361      * should be batched, for example when inflating preferences from XML.
362      *
363      * @return Whether the client should commit.
364      */
shouldCommit()365     boolean shouldCommit() {
366         return !mNoCommit;
367     }
368 
setNoCommit(boolean noCommit)369     private void setNoCommit(boolean noCommit) {
370         if (!noCommit && mEditor != null) {
371             SharedPreferencesCompat.EditorCompat.getInstance().apply(mEditor);
372         }
373         mNoCommit = noCommit;
374     }
375 
376     /**
377      * Returns the context.
378      *
379      * @return The context.
380      */
getContext()381     public Context getContext() {
382         return mContext;
383     }
384 
getOnDisplayPreferenceDialogListener()385     public OnDisplayPreferenceDialogListener getOnDisplayPreferenceDialogListener() {
386         return mOnDisplayPreferenceDialogListener;
387     }
388 
setOnDisplayPreferenceDialogListener( OnDisplayPreferenceDialogListener onDisplayPreferenceDialogListener)389     public void setOnDisplayPreferenceDialogListener(
390             OnDisplayPreferenceDialogListener onDisplayPreferenceDialogListener) {
391         mOnDisplayPreferenceDialogListener = onDisplayPreferenceDialogListener;
392     }
393 
394     /**
395      * Called when a preference requests that a dialog be shown to complete a user interaction.
396      *
397      * @param preference The preference requesting the dialog.
398      */
showDialog(Preference preference)399     public void showDialog(Preference preference) {
400         if (mOnDisplayPreferenceDialogListener != null) {
401             mOnDisplayPreferenceDialogListener.onDisplayPreferenceDialog(preference);
402         }
403     }
404 
405     /**
406      * Sets the callback to be invoked when a {@link Preference} in the
407      * hierarchy rooted at this {@link PreferenceManager} is clicked.
408      *
409      * @param listener The callback to be invoked.
410      */
setOnPreferenceTreeClickListener(OnPreferenceTreeClickListener listener)411     public void setOnPreferenceTreeClickListener(OnPreferenceTreeClickListener listener) {
412         mOnPreferenceTreeClickListener = listener;
413     }
414 
getOnPreferenceTreeClickListener()415     public OnPreferenceTreeClickListener getOnPreferenceTreeClickListener() {
416         return mOnPreferenceTreeClickListener;
417     }
418 
419     /**
420      * Sets the callback to be invoked when a {@link PreferenceScreen} in the hierarchy rooted at
421      * this {@link PreferenceManager} is clicked.
422      *
423      * @param listener The callback to be invoked.
424      */
setOnNavigateToScreenListener(OnNavigateToScreenListener listener)425     public void setOnNavigateToScreenListener(OnNavigateToScreenListener listener) {
426         mOnNavigateToScreenListener = listener;
427     }
428 
429     /**
430      * Returns the {@link PreferenceManager.OnNavigateToScreenListener}, if one has been set.
431      */
getOnNavigateToScreenListener()432     public OnNavigateToScreenListener getOnNavigateToScreenListener() {
433         return mOnNavigateToScreenListener;
434     }
435 
436     /**
437      * Interface definition for a callback to be invoked when a
438      * {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
439      * clicked.
440      */
441     public interface OnPreferenceTreeClickListener {
442         /**
443          * Called when a preference in the tree rooted at this
444          * {@link PreferenceScreen} has been clicked.
445          *
446          * @param preference The preference that was clicked.
447          * @return Whether the click was handled.
448          */
onPreferenceTreeClick(Preference preference)449         boolean onPreferenceTreeClick(Preference preference);
450     }
451 
452     /**
453      * Interface definition for a class that will be called when a
454      * {@link android.support.v7.preference.Preference} requests to display a dialog.
455      */
456     public interface OnDisplayPreferenceDialogListener {
457 
458         /**
459          * Called when a preference in the tree requests to display a dialog.
460          *
461          * @param preference The Preference object requesting the dialog.
462          */
onDisplayPreferenceDialog(Preference preference)463         void onDisplayPreferenceDialog(Preference preference);
464     }
465 
466     /**
467      * Interface definition for a class that will be called when a
468      * {@link android.support.v7.preference.PreferenceScreen} requests navigation.
469      */
470     public interface OnNavigateToScreenListener {
471 
472         /**
473          * Called when a PreferenceScreen in the tree requests to navigate to its contents.
474          *
475          * @param preferenceScreen The PreferenceScreen requesting navigation.
476          */
onNavigateToScreen(PreferenceScreen preferenceScreen)477         void onNavigateToScreen(PreferenceScreen preferenceScreen);
478     }
479 
480 }
481