blob: ebb12fd1291db2d75382f039f47dc61e2d9bb3f8 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.preference;
18
Jeff Sharkeyfd37abe2016-01-28 11:53:48 -070019import android.annotation.SystemApi;
Tor Norbye7b9c9122013-05-30 16:48:33 -070020import android.annotation.XmlRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.app.Activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
23import android.content.DialogInterface;
24import android.content.Intent;
25import android.content.SharedPreferences;
26import android.content.pm.ActivityInfo;
27import android.content.pm.PackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.pm.PackageManager.NameNotFoundException;
Jeff Sharkeyfd37abe2016-01-28 11:53:48 -070029import android.content.pm.ResolveInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.content.res.XmlResourceParser;
31import android.os.Bundle;
32import android.util.Log;
33
Amith Yamasani82e7bc12010-09-23 15:07:58 -070034import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.List;
37
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038/**
39 * Used to help create {@link Preference} hierarchies
40 * from activities or XML.
41 * <p>
42 * In most cases, clients should use
43 * {@link PreferenceActivity#addPreferencesFromIntent} or
44 * {@link PreferenceActivity#addPreferencesFromResource(int)}.
45 *
46 * @see PreferenceActivity
47 */
48public class PreferenceManager {
49
50 private static final String TAG = "PreferenceManager";
51
52 /**
53 * The Activity meta-data key for its XML preference hierarchy.
54 */
55 public static final String METADATA_KEY_PREFERENCES = "android.preference";
56
57 public static final String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
58
59 /**
60 * @see #getActivity()
61 */
62 private Activity mActivity;
63
64 /**
Amith Yamasani82e7bc12010-09-23 15:07:58 -070065 * Fragment that owns this instance.
66 */
67 private PreferenceFragment mFragment;
68
69 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 * The context to use. This should always be set.
71 *
72 * @see #mActivity
73 */
74 private Context mContext;
75
76 /**
77 * The counter for unique IDs.
78 */
79 private long mNextId = 0;
80
81 /**
82 * The counter for unique request codes.
83 */
84 private int mNextRequestCode;
85
86 /**
87 * Cached shared preferences.
88 */
89 private SharedPreferences mSharedPreferences;
90
91 /**
92 * If in no-commit mode, the shared editor to give out (which will be
93 * committed when exiting no-commit mode).
94 */
95 private SharedPreferences.Editor mEditor;
96
97 /**
98 * Blocks commits from happening on the shared editor. This is used when
99 * inflating the hierarchy. Do not set this directly, use {@link #setNoCommit(boolean)}
100 */
101 private boolean mNoCommit;
102
103 /**
104 * The SharedPreferences name that will be used for all {@link Preference}s
105 * managed by this instance.
106 */
107 private String mSharedPreferencesName;
108
109 /**
110 * The SharedPreferences mode that will be used for all {@link Preference}s
111 * managed by this instance.
112 */
113 private int mSharedPreferencesMode;
Jeff Sharkeyfd37abe2016-01-28 11:53:48 -0700114
115 private static final int STORAGE_DEFAULT = 0;
116 private static final int STORAGE_DEVICE_ENCRYPTED = 1;
117 private static final int STORAGE_CREDENTIAL_ENCRYPTED = 2;
118
119 private int mStorage = STORAGE_DEFAULT;
120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 /**
122 * The {@link PreferenceScreen} at the root of the preference hierarchy.
123 */
124 private PreferenceScreen mPreferenceScreen;
125
126 /**
127 * List of activity result listeners.
128 */
129 private List<OnActivityResultListener> mActivityResultListeners;
130
131 /**
132 * List of activity stop listeners.
133 */
134 private List<OnActivityStopListener> mActivityStopListeners;
135
136 /**
137 * List of activity destroy listeners.
138 */
139 private List<OnActivityDestroyListener> mActivityDestroyListeners;
140
141 /**
142 * List of dialogs that should be dismissed when we receive onNewIntent in
143 * our PreferenceActivity.
144 */
145 private List<DialogInterface> mPreferencesScreens;
146
147 private OnPreferenceTreeClickListener mOnPreferenceTreeClickListener;
148
Justin Koh37ae5582012-10-25 15:26:36 -0700149 /**
150 * @hide
151 */
152 public PreferenceManager(Activity activity, int firstRequestCode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 mActivity = activity;
154 mNextRequestCode = firstRequestCode;
155
156 init(activity);
157 }
158
159 /**
160 * This constructor should ONLY be used when getting default values from
161 * an XML preference hierarchy.
162 * <p>
163 * The {@link PreferenceManager#PreferenceManager(Activity)}
164 * should be used ANY time a preference will be displayed, since some preference
165 * types need an Activity for managed queries.
166 */
Deepanshu Gupta10bb1372014-10-05 14:41:17 -0700167 /*package*/ PreferenceManager(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 init(context);
169 }
170
171 private void init(Context context) {
172 mContext = context;
173
174 setSharedPreferencesName(getDefaultSharedPreferencesName(context));
175 }
Amith Yamasani82e7bc12010-09-23 15:07:58 -0700176
177 /**
178 * Sets the owning preference fragment
179 */
180 void setFragment(PreferenceFragment fragment) {
181 mFragment = fragment;
182 }
183
184 /**
185 * Returns the owning preference fragment, if any.
186 */
187 PreferenceFragment getFragment() {
188 return mFragment;
189 }
190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 /**
192 * Returns a list of {@link Activity} (indirectly) that match a given
193 * {@link Intent}.
194 *
195 * @param queryIntent The Intent to match.
196 * @return The list of {@link ResolveInfo} that point to the matched
197 * activities.
198 */
199 private List<ResolveInfo> queryIntentActivities(Intent queryIntent) {
200 return mContext.getPackageManager().queryIntentActivities(queryIntent,
201 PackageManager.GET_META_DATA);
202 }
203
204 /**
205 * Inflates a preference hierarchy from the preference hierarchies of
206 * {@link Activity Activities} that match the given {@link Intent}. An
207 * {@link Activity} defines its preference hierarchy with meta-data using
208 * the {@link #METADATA_KEY_PREFERENCES} key.
209 * <p>
210 * If a preference hierarchy is given, the new preference hierarchies will
211 * be merged in.
212 *
213 * @param queryIntent The intent to match activities.
214 * @param rootPreferences Optional existing hierarchy to merge the new
215 * hierarchies into.
216 * @return The root hierarchy (if one was not provided, the new hierarchy's
217 * root).
218 */
219 PreferenceScreen inflateFromIntent(Intent queryIntent, PreferenceScreen rootPreferences) {
220 final List<ResolveInfo> activities = queryIntentActivities(queryIntent);
221 final HashSet<String> inflatedRes = new HashSet<String>();
222
223 for (int i = activities.size() - 1; i >= 0; i--) {
224 final ActivityInfo activityInfo = activities.get(i).activityInfo;
225 final Bundle metaData = activityInfo.metaData;
226
227 if ((metaData == null) || !metaData.containsKey(METADATA_KEY_PREFERENCES)) {
228 continue;
229 }
230
231 // Need to concat the package with res ID since the same res ID
232 // can be re-used across contexts
233 final String uniqueResId = activityInfo.packageName + ":"
234 + activityInfo.metaData.getInt(METADATA_KEY_PREFERENCES);
235
236 if (!inflatedRes.contains(uniqueResId)) {
237 inflatedRes.add(uniqueResId);
238
239 final Context context;
240 try {
241 context = mContext.createPackageContext(activityInfo.packageName, 0);
242 } catch (NameNotFoundException e) {
243 Log.w(TAG, "Could not create context for " + activityInfo.packageName + ": "
244 + Log.getStackTraceString(e));
245 continue;
246 }
247
248 final PreferenceInflater inflater = new PreferenceInflater(context, this);
249 final XmlResourceParser parser = activityInfo.loadXmlMetaData(context
250 .getPackageManager(), METADATA_KEY_PREFERENCES);
251 rootPreferences = (PreferenceScreen) inflater
252 .inflate(parser, rootPreferences, true);
253 parser.close();
254 }
255 }
256
257 rootPreferences.onAttachedToHierarchy(this);
258
259 return rootPreferences;
260 }
261
262 /**
263 * Inflates a preference hierarchy from XML. If a preference hierarchy is
264 * given, the new preference hierarchies will be merged in.
265 *
266 * @param context The context of the resource.
267 * @param resId The resource ID of the XML to inflate.
268 * @param rootPreferences Optional existing hierarchy to merge the new
269 * hierarchies into.
270 * @return The root hierarchy (if one was not provided, the new hierarchy's
271 * root).
Owen Linf9b702e2009-08-27 18:30:05 +0800272 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700274 public PreferenceScreen inflateFromResource(Context context, @XmlRes int resId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 PreferenceScreen rootPreferences) {
276 // Block commits
277 setNoCommit(true);
278
279 final PreferenceInflater inflater = new PreferenceInflater(context, this);
280 rootPreferences = (PreferenceScreen) inflater.inflate(resId, rootPreferences, true);
281 rootPreferences.onAttachedToHierarchy(this);
282
283 // Unblock commits
284 setNoCommit(false);
285
286 return rootPreferences;
287 }
288
289 public PreferenceScreen createPreferenceScreen(Context context) {
290 final PreferenceScreen preferenceScreen = new PreferenceScreen(context, null);
291 preferenceScreen.onAttachedToHierarchy(this);
292 return preferenceScreen;
293 }
294
295 /**
296 * Called by a preference to get a unique ID in its hierarchy.
297 *
298 * @return A unique ID.
299 */
300 long getNextId() {
301 synchronized (this) {
302 return mNextId++;
303 }
304 }
305
306 /**
307 * Returns the current name of the SharedPreferences file that preferences managed by
308 * this will use.
309 *
310 * @return The name that can be passed to {@link Context#getSharedPreferences(String, int)}.
311 * @see Context#getSharedPreferences(String, int)
312 */
313 public String getSharedPreferencesName() {
314 return mSharedPreferencesName;
315 }
316
317 /**
318 * Sets the name of the SharedPreferences file that preferences managed by this
319 * will use.
320 *
321 * @param sharedPreferencesName The name of the SharedPreferences file.
322 * @see Context#getSharedPreferences(String, int)
323 */
324 public void setSharedPreferencesName(String sharedPreferencesName) {
325 mSharedPreferencesName = sharedPreferencesName;
326 mSharedPreferences = null;
327 }
328
329 /**
330 * Returns the current mode of the SharedPreferences file that preferences managed by
331 * this will use.
332 *
333 * @return The mode that can be passed to {@link Context#getSharedPreferences(String, int)}.
334 * @see Context#getSharedPreferences(String, int)
335 */
336 public int getSharedPreferencesMode() {
337 return mSharedPreferencesMode;
338 }
339
340 /**
341 * Sets the mode of the SharedPreferences file that preferences managed by this
342 * will use.
343 *
344 * @param sharedPreferencesMode The mode of the SharedPreferences file.
345 * @see Context#getSharedPreferences(String, int)
346 */
347 public void setSharedPreferencesMode(int sharedPreferencesMode) {
348 mSharedPreferencesMode = sharedPreferencesMode;
349 mSharedPreferences = null;
350 }
351
352 /**
Jeff Sharkeyfd37abe2016-01-28 11:53:48 -0700353 * Sets the storage location used internally by this class to be the default
354 * provided by the hosting {@link Context}.
355 */
356 public void setStorageDefault() {
357 mStorage = STORAGE_DEFAULT;
358 mSharedPreferences = null;
359 }
360
361 /**
362 * Explicitly set the storage location used internally by this class to be
363 * device-encrypted storage.
364 * <p>
365 * Data stored in device-encrypted storage is typically encrypted with a key
366 * tied to the physical device, and it can be accessed when the device has
367 * booted successfully, both <em>before and after</em> the user has
368 * authenticated with their credentials (such as a lock pattern or PIN).
369 * Because device-encrypted data is available before user authentication,
370 * you should carefully consider what data you store using this mode.
371 *
372 * @see Context#createDeviceEncryptedStorageContext()
373 */
374 public void setStorageDeviceEncrypted() {
375 mStorage = STORAGE_DEVICE_ENCRYPTED;
376 mSharedPreferences = null;
377 }
378
379 /**
380 * Explicitly set the storage location used internally by this class to be
381 * credential-encrypted storage.
382 *
383 * @see Context#createCredentialEncryptedStorageContext()
384 * @hide
385 */
386 @SystemApi
387 public void setStorageCredentialEncrypted() {
388 mStorage = STORAGE_CREDENTIAL_ENCRYPTED;
389 mSharedPreferences = null;
390 }
391
392 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 * Gets a SharedPreferences instance that preferences managed by this will
394 * use.
395 *
396 * @return A SharedPreferences instance pointing to the file that contains
397 * the values of preferences that are managed by this.
398 */
399 public SharedPreferences getSharedPreferences() {
400 if (mSharedPreferences == null) {
Jeff Sharkeyfd37abe2016-01-28 11:53:48 -0700401 final Context storageContext;
402 switch (mStorage) {
403 case STORAGE_DEVICE_ENCRYPTED:
404 storageContext = mContext.createDeviceEncryptedStorageContext();
405 break;
406 case STORAGE_CREDENTIAL_ENCRYPTED:
407 storageContext = mContext.createCredentialEncryptedStorageContext();
408 break;
409 default:
410 storageContext = mContext;
411 break;
412 }
413
414 mSharedPreferences = storageContext.getSharedPreferences(mSharedPreferencesName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 mSharedPreferencesMode);
416 }
417
418 return mSharedPreferences;
419 }
420
421 /**
422 * Gets a SharedPreferences instance that points to the default file that is
423 * used by the preference framework in the given context.
424 *
425 * @param context The context of the preferences whose values are wanted.
426 * @return A SharedPreferences instance that can be used to retrieve and
427 * listen to values of the preferences.
428 */
429 public static SharedPreferences getDefaultSharedPreferences(Context context) {
430 return context.getSharedPreferences(getDefaultSharedPreferencesName(context),
431 getDefaultSharedPreferencesMode());
432 }
433
Jeff Sharkey6a6cdaf2015-12-07 19:25:19 -0700434 /**
435 * Returns the name used for storing default shared preferences.
436 *
437 * @see #getDefaultSharedPreferences(Context)
438 * @see Context#getSharedPreferencesPath(String)
439 */
440 public static String getDefaultSharedPreferencesName(Context context) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 return context.getPackageName() + "_preferences";
442 }
443
444 private static int getDefaultSharedPreferencesMode() {
445 return Context.MODE_PRIVATE;
446 }
447
448 /**
449 * Returns the root of the preference hierarchy managed by this class.
450 *
451 * @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
452 */
453 PreferenceScreen getPreferenceScreen() {
454 return mPreferenceScreen;
455 }
456
457 /**
458 * Sets the root of the preference hierarchy.
459 *
460 * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
461 * @return Whether the {@link PreferenceScreen} given is different than the previous.
462 */
463 boolean setPreferences(PreferenceScreen preferenceScreen) {
464 if (preferenceScreen != mPreferenceScreen) {
Jason Monke18dc502015-08-11 16:40:44 -0400465 if (mPreferenceScreen != null) {
466 mPreferenceScreen.onDetachedFromActivity();
467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 mPreferenceScreen = preferenceScreen;
469 return true;
470 }
471
472 return false;
473 }
474
475 /**
476 * Finds a {@link Preference} based on its key.
477 *
478 * @param key The key of the preference to retrieve.
479 * @return The {@link Preference} with the key, or null.
480 * @see PreferenceGroup#findPreference(CharSequence)
481 */
482 public Preference findPreference(CharSequence key) {
483 if (mPreferenceScreen == null) {
484 return null;
485 }
486
487 return mPreferenceScreen.findPreference(key);
488 }
489
490 /**
Scott Mainbbb3f412012-03-09 19:10:40 -0800491 * Sets the default values from an XML preference file by reading the values defined
492 * by each {@link Preference} item's {@code android:defaultValue} attribute. This should
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 * be called by the application's main activity.
494 * <p>
Scott Mainbbb3f412012-03-09 19:10:40 -0800495 *
496 * @param context The context of the shared preferences.
497 * @param resId The resource ID of the preference XML file.
498 * @param readAgain Whether to re-read the default values.
499 * If false, this method sets the default values only if this
500 * method has never been called in the past (or if the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 * {@link #KEY_HAS_SET_DEFAULT_VALUES} in the default value shared
502 * preferences file is false). To attempt to set the default values again
503 * bypassing this check, set {@code readAgain} to true.
Scott Mainbbb3f412012-03-09 19:10:40 -0800504 * <p class="note">
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 * Note: this will NOT reset preferences back to their default
506 * values. For that functionality, use
507 * {@link PreferenceManager#getDefaultSharedPreferences(Context)}
508 * and clear it followed by a call to this method with this
509 * parameter set to true.
510 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700511 public static void setDefaultValues(Context context, @XmlRes int resId, boolean readAgain) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512
513 // Use the default shared preferences name and mode
514 setDefaultValues(context, getDefaultSharedPreferencesName(context),
515 getDefaultSharedPreferencesMode(), resId, readAgain);
516 }
517
518 /**
519 * Similar to {@link #setDefaultValues(Context, int, boolean)} but allows
520 * the client to provide the filename and mode of the shared preferences
521 * file.
Scott Mainbbb3f412012-03-09 19:10:40 -0800522 *
523 * @param context The context of the shared preferences.
524 * @param sharedPreferencesName A custom name for the shared preferences file.
525 * @param sharedPreferencesMode The file creation mode for the shared preferences file, such
526 * as {@link android.content.Context#MODE_PRIVATE} or {@link
527 * android.content.Context#MODE_PRIVATE}
528 * @param resId The resource ID of the preference XML file.
529 * @param readAgain Whether to re-read the default values.
530 * If false, this method will set the default values only if this
531 * method has never been called in the past (or if the
532 * {@link #KEY_HAS_SET_DEFAULT_VALUES} in the default value shared
533 * preferences file is false). To attempt to set the default values again
534 * bypassing this check, set {@code readAgain} to true.
535 * <p class="note">
536 * Note: this will NOT reset preferences back to their default
537 * values. For that functionality, use
538 * {@link PreferenceManager#getDefaultSharedPreferences(Context)}
539 * and clear it followed by a call to this method with this
540 * parameter set to true.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 *
542 * @see #setDefaultValues(Context, int, boolean)
543 * @see #setSharedPreferencesName(String)
544 * @see #setSharedPreferencesMode(int)
545 */
546 public static void setDefaultValues(Context context, String sharedPreferencesName,
547 int sharedPreferencesMode, int resId, boolean readAgain) {
548 final SharedPreferences defaultValueSp = context.getSharedPreferences(
549 KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE);
550
551 if (readAgain || !defaultValueSp.getBoolean(KEY_HAS_SET_DEFAULT_VALUES, false)) {
552 final PreferenceManager pm = new PreferenceManager(context);
553 pm.setSharedPreferencesName(sharedPreferencesName);
554 pm.setSharedPreferencesMode(sharedPreferencesMode);
555 pm.inflateFromResource(context, resId, null);
556
Brad Fitzpatrickdd644c12010-10-10 10:58:47 -0700557 SharedPreferences.Editor editor =
558 defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true);
559 try {
560 editor.apply();
561 } catch (AbstractMethodError unused) {
562 // The app injected its own pre-Gingerbread
563 // SharedPreferences.Editor implementation without
564 // an apply method.
565 editor.commit();
566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568 }
569
570 /**
571 * Returns an editor to use when modifying the shared preferences.
572 * <p>
573 * Do NOT commit unless {@link #shouldCommit()} returns true.
574 *
575 * @return An editor to use to write to shared preferences.
576 * @see #shouldCommit()
577 */
578 SharedPreferences.Editor getEditor() {
579
580 if (mNoCommit) {
581 if (mEditor == null) {
582 mEditor = getSharedPreferences().edit();
583 }
584
585 return mEditor;
586 } else {
587 return getSharedPreferences().edit();
588 }
589 }
590
591 /**
592 * Whether it is the client's responsibility to commit on the
593 * {@link #getEditor()}. This will return false in cases where the writes
594 * should be batched, for example when inflating preferences from XML.
595 *
596 * @return Whether the client should commit.
597 */
598 boolean shouldCommit() {
599 return !mNoCommit;
600 }
Brad Fitzpatrickdd644c12010-10-10 10:58:47 -0700601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 private void setNoCommit(boolean noCommit) {
603 if (!noCommit && mEditor != null) {
Brad Fitzpatrickdd644c12010-10-10 10:58:47 -0700604 try {
605 mEditor.apply();
606 } catch (AbstractMethodError unused) {
607 // The app injected its own pre-Gingerbread
608 // SharedPreferences.Editor implementation without
609 // an apply method.
610 mEditor.commit();
611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 mNoCommit = noCommit;
614 }
Brad Fitzpatrickdd644c12010-10-10 10:58:47 -0700615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 /**
617 * Returns the activity that shows the preferences. This is useful for doing
618 * managed queries, but in most cases the use of {@link #getContext()} is
619 * preferred.
620 * <p>
621 * This will return null if this class was instantiated with a Context
622 * instead of Activity. For example, when setting the default values.
623 *
624 * @return The activity that shows the preferences.
625 * @see #mContext
626 */
627 Activity getActivity() {
628 return mActivity;
629 }
630
631 /**
632 * Returns the context. This is preferred over {@link #getActivity()} when
633 * possible.
634 *
635 * @return The context.
636 */
637 Context getContext() {
638 return mContext;
639 }
640
641 /**
642 * Registers a listener.
643 *
644 * @see OnActivityResultListener
645 */
646 void registerOnActivityResultListener(OnActivityResultListener listener) {
647 synchronized (this) {
648 if (mActivityResultListeners == null) {
649 mActivityResultListeners = new ArrayList<OnActivityResultListener>();
650 }
651
652 if (!mActivityResultListeners.contains(listener)) {
653 mActivityResultListeners.add(listener);
654 }
655 }
656 }
657
658 /**
659 * Unregisters a listener.
660 *
661 * @see OnActivityResultListener
662 */
663 void unregisterOnActivityResultListener(OnActivityResultListener listener) {
664 synchronized (this) {
665 if (mActivityResultListeners != null) {
666 mActivityResultListeners.remove(listener);
667 }
668 }
669 }
670
671 /**
672 * Called by the {@link PreferenceManager} to dispatch a subactivity result.
673 */
674 void dispatchActivityResult(int requestCode, int resultCode, Intent data) {
675 List<OnActivityResultListener> list;
676
677 synchronized (this) {
678 if (mActivityResultListeners == null) return;
679 list = new ArrayList<OnActivityResultListener>(mActivityResultListeners);
680 }
681
682 final int N = list.size();
683 for (int i = 0; i < N; i++) {
684 if (list.get(i).onActivityResult(requestCode, resultCode, data)) {
685 break;
686 }
687 }
688 }
689
690 /**
691 * Registers a listener.
692 *
693 * @see OnActivityStopListener
John Spurlock74a2e062014-05-16 21:03:29 -0400694 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 */
John Spurlock74a2e062014-05-16 21:03:29 -0400696 public void registerOnActivityStopListener(OnActivityStopListener listener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 synchronized (this) {
698 if (mActivityStopListeners == null) {
699 mActivityStopListeners = new ArrayList<OnActivityStopListener>();
700 }
701
702 if (!mActivityStopListeners.contains(listener)) {
703 mActivityStopListeners.add(listener);
704 }
705 }
706 }
707
708 /**
709 * Unregisters a listener.
710 *
711 * @see OnActivityStopListener
John Spurlock74a2e062014-05-16 21:03:29 -0400712 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 */
John Spurlock74a2e062014-05-16 21:03:29 -0400714 public void unregisterOnActivityStopListener(OnActivityStopListener listener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 synchronized (this) {
716 if (mActivityStopListeners != null) {
717 mActivityStopListeners.remove(listener);
718 }
719 }
720 }
721
722 /**
723 * Called by the {@link PreferenceManager} to dispatch the activity stop
724 * event.
725 */
726 void dispatchActivityStop() {
727 List<OnActivityStopListener> list;
728
729 synchronized (this) {
730 if (mActivityStopListeners == null) return;
731 list = new ArrayList<OnActivityStopListener>(mActivityStopListeners);
732 }
733
734 final int N = list.size();
735 for (int i = 0; i < N; i++) {
736 list.get(i).onActivityStop();
737 }
738 }
739
740 /**
741 * Registers a listener.
742 *
743 * @see OnActivityDestroyListener
744 */
745 void registerOnActivityDestroyListener(OnActivityDestroyListener listener) {
746 synchronized (this) {
747 if (mActivityDestroyListeners == null) {
748 mActivityDestroyListeners = new ArrayList<OnActivityDestroyListener>();
749 }
750
751 if (!mActivityDestroyListeners.contains(listener)) {
752 mActivityDestroyListeners.add(listener);
753 }
754 }
755 }
756
757 /**
758 * Unregisters a listener.
759 *
760 * @see OnActivityDestroyListener
761 */
762 void unregisterOnActivityDestroyListener(OnActivityDestroyListener listener) {
763 synchronized (this) {
764 if (mActivityDestroyListeners != null) {
765 mActivityDestroyListeners.remove(listener);
766 }
767 }
768 }
769
770 /**
771 * Called by the {@link PreferenceManager} to dispatch the activity destroy
772 * event.
773 */
774 void dispatchActivityDestroy() {
775 List<OnActivityDestroyListener> list = null;
Jason Monke18dc502015-08-11 16:40:44 -0400776
777 if (mPreferenceScreen != null) {
778 mPreferenceScreen.onDetachedFromActivity();
779 mPreferenceScreen = null;
780 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 synchronized (this) {
782 if (mActivityDestroyListeners != null) {
783 list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
784 }
785 }
786
787 if (list != null) {
788 final int N = list.size();
789 for (int i = 0; i < N; i++) {
790 list.get(i).onActivityDestroy();
791 }
792 }
793
794 // Dismiss any PreferenceScreens still showing
795 dismissAllScreens();
796 }
797
798 /**
799 * Returns a request code that is unique for the activity. Each subsequent
800 * call to this method should return another unique request code.
801 *
802 * @return A unique request code that will never be used by anyone other
803 * than the caller of this method.
804 */
805 int getNextRequestCode() {
806 synchronized (this) {
807 return mNextRequestCode++;
808 }
809 }
810
811 void addPreferencesScreen(DialogInterface screen) {
812 synchronized (this) {
813
814 if (mPreferencesScreens == null) {
815 mPreferencesScreens = new ArrayList<DialogInterface>();
816 }
817
818 mPreferencesScreens.add(screen);
819 }
820 }
821
822 void removePreferencesScreen(DialogInterface screen) {
823 synchronized (this) {
824
825 if (mPreferencesScreens == null) {
826 return;
827 }
828
829 mPreferencesScreens.remove(screen);
830 }
831 }
832
833 /**
834 * Called by {@link PreferenceActivity} to dispatch the new Intent event.
835 *
836 * @param intent The new Intent.
837 */
838 void dispatchNewIntent(Intent intent) {
839 dismissAllScreens();
840 }
841
842 private void dismissAllScreens() {
843 // Remove any of the previously shown preferences screens
844 ArrayList<DialogInterface> screensToDismiss;
845
846 synchronized (this) {
847
848 if (mPreferencesScreens == null) {
849 return;
850 }
851
852 screensToDismiss = new ArrayList<DialogInterface>(mPreferencesScreens);
853 mPreferencesScreens.clear();
854 }
855
856 for (int i = screensToDismiss.size() - 1; i >= 0; i--) {
857 screensToDismiss.get(i).dismiss();
858 }
859 }
860
861 /**
862 * Sets the callback to be invoked when a {@link Preference} in the
863 * hierarchy rooted at this {@link PreferenceManager} is clicked.
864 *
865 * @param listener The callback to be invoked.
866 */
867 void setOnPreferenceTreeClickListener(OnPreferenceTreeClickListener listener) {
868 mOnPreferenceTreeClickListener = listener;
869 }
870
871 OnPreferenceTreeClickListener getOnPreferenceTreeClickListener() {
872 return mOnPreferenceTreeClickListener;
873 }
874
875 /**
876 * Interface definition for a callback to be invoked when a
877 * {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
878 * clicked.
Fabrice Di Meglioad2fcfe2014-01-20 11:10:52 -0800879 *
880 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 */
Fabrice Di Meglioad2fcfe2014-01-20 11:10:52 -0800882 public interface OnPreferenceTreeClickListener {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 /**
884 * Called when a preference in the tree rooted at this
885 * {@link PreferenceScreen} has been clicked.
886 *
887 * @param preferenceScreen The {@link PreferenceScreen} that the
888 * preference is located in.
889 * @param preference The preference that was clicked.
890 * @return Whether the click was handled.
891 */
892 boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference);
893 }
894
895 /**
896 * Interface definition for a class that will be called when the container's activity
897 * receives an activity result.
898 */
899 public interface OnActivityResultListener {
900
901 /**
902 * See Activity's onActivityResult.
903 *
904 * @return Whether the request code was handled (in which case
905 * subsequent listeners will not be called.
906 */
907 boolean onActivityResult(int requestCode, int resultCode, Intent data);
908 }
909
910 /**
911 * Interface definition for a class that will be called when the container's activity
912 * is stopped.
913 */
914 public interface OnActivityStopListener {
915
916 /**
917 * See Activity's onStop.
918 */
919 void onActivityStop();
920 }
921
922 /**
923 * Interface definition for a class that will be called when the container's activity
924 * is destroyed.
925 */
926 public interface OnActivityDestroyListener {
927
928 /**
929 * See Activity's onDestroy.
930 */
931 void onActivityDestroy();
932 }
933
934}