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