• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.ListActivity;
21 import android.content.Intent;
22 import android.content.SharedPreferences;
23 import android.os.Bundle;
24 import android.os.Handler;
25 import android.os.Message;
26 import android.view.View;
27 
28 /**
29  * Shows a hierarchy of {@link Preference} objects as
30  * lists, possibly spanning multiple screens. These preferences will
31  * automatically save to {@link SharedPreferences} as the user interacts with
32  * them. To retrieve an instance of {@link SharedPreferences} that the
33  * preference hierarchy in this activity will use, call
34  * {@link PreferenceManager#getDefaultSharedPreferences(android.content.Context)}
35  * with a context in the same package as this activity.
36  * <p>
37  * Furthermore, the preferences shown will follow the visual style of system
38  * preferences. It is easy to create a hierarchy of preferences (that can be
39  * shown on multiple screens) via XML. For these reasons, it is recommended to
40  * use this activity (as a superclass) to deal with preferences in applications.
41  * <p>
42  * A {@link PreferenceScreen} object should be at the top of the preference
43  * hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
44  * denote a screen break--that is the preferences contained within subsequent
45  * {@link PreferenceScreen} should be shown on another screen. The preference
46  * framework handles showing these other screens from the preference hierarchy.
47  * <p>
48  * The preference hierarchy can be formed in multiple ways:
49  * <li> From an XML file specifying the hierarchy
50  * <li> From different {@link Activity Activities} that each specify its own
51  * preferences in an XML file via {@link Activity} meta-data
52  * <li> From an object hierarchy rooted with {@link PreferenceScreen}
53  * <p>
54  * To inflate from XML, use the {@link #addPreferencesFromResource(int)}. The
55  * root element should be a {@link PreferenceScreen}. Subsequent elements can point
56  * to actual {@link Preference} subclasses. As mentioned above, subsequent
57  * {@link PreferenceScreen} in the hierarchy will result in the screen break.
58  * <p>
59  * To specify an {@link Intent} to query {@link Activity Activities} that each
60  * have preferences, use {@link #addPreferencesFromIntent}. Each
61  * {@link Activity} can specify meta-data in the manifest (via the key
62  * {@link PreferenceManager#METADATA_KEY_PREFERENCES}) that points to an XML
63  * resource. These XML resources will be inflated into a single preference
64  * hierarchy and shown by this activity.
65  * <p>
66  * To specify an object hierarchy rooted with {@link PreferenceScreen}, use
67  * {@link #setPreferenceScreen(PreferenceScreen)}.
68  * <p>
69  * As a convenience, this activity implements a click listener for any
70  * preference in the current hierarchy, see
71  * {@link #onPreferenceTreeClick(PreferenceScreen, Preference)}.
72  *
73  * @see Preference
74  * @see PreferenceScreen
75  */
76 public abstract class PreferenceActivity extends ListActivity implements
77         PreferenceManager.OnPreferenceTreeClickListener {
78 
79     private static final String PREFERENCES_TAG = "android:preferences";
80 
81     private PreferenceManager mPreferenceManager;
82 
83     private Bundle mSavedInstanceState;
84 
85     /**
86      * The starting request code given out to preference framework.
87      */
88     private static final int FIRST_REQUEST_CODE = 100;
89 
90     private static final int MSG_BIND_PREFERENCES = 0;
91     private Handler mHandler = new Handler() {
92         @Override
93         public void handleMessage(Message msg) {
94             switch (msg.what) {
95 
96                 case MSG_BIND_PREFERENCES:
97                     bindPreferences();
98                     break;
99             }
100         }
101     };
102 
103     @Override
onCreate(Bundle savedInstanceState)104     protected void onCreate(Bundle savedInstanceState) {
105         super.onCreate(savedInstanceState);
106 
107         setContentView(com.android.internal.R.layout.preference_list_content);
108 
109         mPreferenceManager = onCreatePreferenceManager();
110         getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
111     }
112 
113     @Override
onStop()114     protected void onStop() {
115         super.onStop();
116 
117         mPreferenceManager.dispatchActivityStop();
118     }
119 
120     @Override
onDestroy()121     protected void onDestroy() {
122         super.onDestroy();
123 
124         mPreferenceManager.dispatchActivityDestroy();
125     }
126 
127     @Override
onSaveInstanceState(Bundle outState)128     protected void onSaveInstanceState(Bundle outState) {
129         super.onSaveInstanceState(outState);
130 
131         final PreferenceScreen preferenceScreen = getPreferenceScreen();
132         if (preferenceScreen != null) {
133             Bundle container = new Bundle();
134             preferenceScreen.saveHierarchyState(container);
135             outState.putBundle(PREFERENCES_TAG, container);
136         }
137     }
138 
139     @Override
onRestoreInstanceState(Bundle state)140     protected void onRestoreInstanceState(Bundle state) {
141         Bundle container = state.getBundle(PREFERENCES_TAG);
142         if (container != null) {
143             final PreferenceScreen preferenceScreen = getPreferenceScreen();
144             if (preferenceScreen != null) {
145                 preferenceScreen.restoreHierarchyState(container);
146                 mSavedInstanceState = state;
147                 return;
148             }
149         }
150 
151         // Only call this if we didn't save the instance state for later.
152         // If we did save it, it will be restored when we bind the adapter.
153         super.onRestoreInstanceState(state);
154     }
155 
156     @Override
onActivityResult(int requestCode, int resultCode, Intent data)157     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
158         super.onActivityResult(requestCode, resultCode, data);
159 
160         mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
161     }
162 
163     @Override
onContentChanged()164     public void onContentChanged() {
165         super.onContentChanged();
166         postBindPreferences();
167     }
168 
169     /**
170      * Posts a message to bind the preferences to the list view.
171      * <p>
172      * Binding late is preferred as any custom preference types created in
173      * {@link #onCreate(Bundle)} are able to have their views recycled.
174      */
postBindPreferences()175     private void postBindPreferences() {
176         if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
177         mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
178     }
179 
bindPreferences()180     private void bindPreferences() {
181         final PreferenceScreen preferenceScreen = getPreferenceScreen();
182         if (preferenceScreen != null) {
183             preferenceScreen.bind(getListView());
184             if (mSavedInstanceState != null) {
185                 super.onRestoreInstanceState(mSavedInstanceState);
186                 mSavedInstanceState = null;
187             }
188         }
189     }
190 
191     /**
192      * Creates the {@link PreferenceManager}.
193      *
194      * @return The {@link PreferenceManager} used by this activity.
195      */
onCreatePreferenceManager()196     private PreferenceManager onCreatePreferenceManager() {
197         PreferenceManager preferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
198         preferenceManager.setOnPreferenceTreeClickListener(this);
199         return preferenceManager;
200     }
201 
202     /**
203      * Returns the {@link PreferenceManager} used by this activity.
204      * @return The {@link PreferenceManager}.
205      */
getPreferenceManager()206     public PreferenceManager getPreferenceManager() {
207         return mPreferenceManager;
208     }
209 
requirePreferenceManager()210     private void requirePreferenceManager() {
211         if (mPreferenceManager == null) {
212             throw new RuntimeException("This should be called after super.onCreate.");
213         }
214     }
215 
216     /**
217      * Sets the root of the preference hierarchy that this activity is showing.
218      *
219      * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
220      */
setPreferenceScreen(PreferenceScreen preferenceScreen)221     public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
222         if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
223             postBindPreferences();
224             CharSequence title = getPreferenceScreen().getTitle();
225             // Set the title of the activity
226             if (title != null) {
227                 setTitle(title);
228             }
229         }
230     }
231 
232     /**
233      * Gets the root of the preference hierarchy that this activity is showing.
234      *
235      * @return The {@link PreferenceScreen} that is the root of the preference
236      *         hierarchy.
237      */
getPreferenceScreen()238     public PreferenceScreen getPreferenceScreen() {
239         return mPreferenceManager.getPreferenceScreen();
240     }
241 
242     /**
243      * Adds preferences from activities that match the given {@link Intent}.
244      *
245      * @param intent The {@link Intent} to query activities.
246      */
addPreferencesFromIntent(Intent intent)247     public void addPreferencesFromIntent(Intent intent) {
248         requirePreferenceManager();
249 
250         setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
251     }
252 
253     /**
254      * Inflates the given XML resource and adds the preference hierarchy to the current
255      * preference hierarchy.
256      *
257      * @param preferencesResId The XML resource ID to inflate.
258      */
addPreferencesFromResource(int preferencesResId)259     public void addPreferencesFromResource(int preferencesResId) {
260         requirePreferenceManager();
261 
262         setPreferenceScreen(mPreferenceManager.inflateFromResource(this, preferencesResId,
263                 getPreferenceScreen()));
264     }
265 
266     /**
267      * {@inheritDoc}
268      */
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)269     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
270         return false;
271     }
272 
273     /**
274      * Finds a {@link Preference} based on its key.
275      *
276      * @param key The key of the preference to retrieve.
277      * @return The {@link Preference} with the key, or null.
278      * @see PreferenceGroup#findPreference(CharSequence)
279      */
findPreference(CharSequence key)280     public Preference findPreference(CharSequence key) {
281 
282         if (mPreferenceManager == null) {
283             return null;
284         }
285 
286         return mPreferenceManager.findPreference(key);
287     }
288 
289     @Override
onNewIntent(Intent intent)290     protected void onNewIntent(Intent intent) {
291         if (mPreferenceManager != null) {
292             mPreferenceManager.dispatchNewIntent(intent);
293         }
294     }
295 
296 }
297