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