PreferenceActivity.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
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        requestWindowFeature(Window.FEATURE_NO_TITLE);
107
108        setContentView(com.android.internal.R.layout.preference_list_content);
109
110        mPreferenceManager = onCreatePreferenceManager();
111        getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
112    }
113
114    @Override
115    protected void onStop() {
116        super.onStop();
117
118        mPreferenceManager.dispatchActivityStop();
119    }
120
121    @Override
122    protected void onDestroy() {
123        super.onDestroy();
124
125        mPreferenceManager.dispatchActivityDestroy();
126    }
127
128    @Override
129    protected void onSaveInstanceState(Bundle outState) {
130        super.onSaveInstanceState(outState);
131
132        final PreferenceScreen preferenceScreen = getPreferenceScreen();
133        if (preferenceScreen != null) {
134            Bundle container = new Bundle();
135            preferenceScreen.saveHierarchyState(container);
136            outState.putBundle(PREFERENCES_TAG, container);
137        }
138    }
139
140    @Override
141    protected void onRestoreInstanceState(Bundle state) {
142        super.onRestoreInstanceState(state);
143
144        Bundle container = state.getBundle(PREFERENCES_TAG);
145        if (container != null) {
146            final PreferenceScreen preferenceScreen = getPreferenceScreen();
147            if (preferenceScreen != null) {
148                preferenceScreen.restoreHierarchyState(container);
149            }
150        }
151    }
152
153    @Override
154    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
155        super.onActivityResult(requestCode, resultCode, data);
156
157        mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
158    }
159
160    @Override
161    public void onContentChanged() {
162        super.onContentChanged();
163        postBindPreferences();
164    }
165
166    /**
167     * Posts a message to bind the preferences to the list view.
168     * <p>
169     * Binding late is preferred as any custom preference types created in
170     * {@link #onCreate(Bundle)} are able to have their views recycled.
171     */
172    private void postBindPreferences() {
173        if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
174        mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
175    }
176
177    private void bindPreferences() {
178        final PreferenceScreen preferenceScreen = getPreferenceScreen();
179        if (preferenceScreen != null) {
180            preferenceScreen.bind(getListView());
181        }
182    }
183
184    /**
185     * Creates the {@link PreferenceManager}.
186     *
187     * @return The {@link PreferenceManager} used by this activity.
188     */
189    private PreferenceManager onCreatePreferenceManager() {
190        PreferenceManager preferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
191        preferenceManager.setOnPreferenceTreeClickListener(this);
192        return preferenceManager;
193    }
194
195    /**
196     * Returns the {@link PreferenceManager} used by this activity.
197     * @return The {@link PreferenceManager}.
198     */
199    public PreferenceManager getPreferenceManager() {
200        return mPreferenceManager;
201    }
202
203    private void requirePreferenceManager() {
204        if (mPreferenceManager == null) {
205            throw new RuntimeException("This should be called after super.onCreate.");
206        }
207    }
208
209    /**
210     * Sets the root of the preference hierarchy that this activity is showing.
211     *
212     * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
213     */
214    public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
215        if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
216            postBindPreferences();
217        }
218    }
219
220    /**
221     * Gets the root of the preference hierarchy that this activity is showing.
222     *
223     * @return The {@link PreferenceScreen} that is the root of the preference
224     *         hierarchy.
225     */
226    public PreferenceScreen getPreferenceScreen() {
227        return mPreferenceManager.getPreferenceScreen();
228    }
229
230    /**
231     * Adds preferences from activities that match the given {@link Intent}.
232     *
233     * @param intent The {@link Intent} to query activities.
234     */
235    public void addPreferencesFromIntent(Intent intent) {
236        requirePreferenceManager();
237
238        setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
239    }
240
241    /**
242     * Inflates the given XML resource and adds the preference hierarchy to the current
243     * preference hierarchy.
244     *
245     * @param preferencesResId The XML resource ID to inflate.
246     */
247    public void addPreferencesFromResource(int preferencesResId) {
248        requirePreferenceManager();
249
250        setPreferenceScreen(mPreferenceManager.inflateFromResource(this, preferencesResId,
251                getPreferenceScreen()));
252    }
253
254    /**
255     * {@inheritDoc}
256     */
257    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
258        return false;
259    }
260
261    /**
262     * Finds a {@link Preference} based on its key.
263     *
264     * @param key The key of the preference to retrieve.
265     * @return The {@link Preference} with the key, or null.
266     * @see PreferenceGroup#findPreference(CharSequence)
267     */
268    public Preference findPreference(CharSequence key) {
269
270        if (mPreferenceManager == null) {
271            return null;
272        }
273
274        return mPreferenceManager.findPreference(key);
275    }
276
277    @Override
278    protected void onNewIntent(Intent intent) {
279        if (mPreferenceManager != null) {
280            mPreferenceManager.dispatchNewIntent(intent);
281        }
282    }
283
284}
285