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