PreferenceScreen.java revision 72e6bece43ca2778d8101a6d4dede2a12e0d47e8
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.Dialog; 20import android.content.Context; 21import android.content.DialogInterface; 22import android.os.Bundle; 23import android.os.Parcel; 24import android.os.Parcelable; 25import android.text.TextUtils; 26import android.util.AttributeSet; 27import android.view.View; 28import android.view.Window; 29import android.widget.Adapter; 30import android.widget.AdapterView; 31import android.widget.ListAdapter; 32import android.widget.ListView; 33 34/** 35 * Represents a top-level {@link Preference} that 36 * is the root of a Preference hierarchy. A {@link PreferenceActivity} 37 * points to an instance of this class to show the preferences. To instantiate 38 * this class, use {@link PreferenceManager#createPreferenceScreen(Context)}. 39 * <ul> 40 * This class can appear in two places: 41 * <li> When a {@link PreferenceActivity} points to this, it is used as the root 42 * and is not shown (only the contained preferences are shown). 43 * <li> When it appears inside another preference hierarchy, it is shown and 44 * serves as the gateway to another screen of preferences (either by showing 45 * another screen of preferences as a {@link Dialog} or via a 46 * {@link Context#startActivity(android.content.Intent)} from the 47 * {@link Preference#getIntent()}). The children of this {@link PreferenceScreen} 48 * are NOT shown in the screen that this {@link PreferenceScreen} is shown in. 49 * Instead, a separate screen will be shown when this preference is clicked. 50 * </ul> 51 * <p>Here's an example XML layout of a PreferenceScreen:</p> 52 * <pre> 53<PreferenceScreen 54 xmlns:android="http://schemas.android.com/apk/res/android" 55 android:key="first_preferencescreen"> 56 <CheckBoxPreference 57 android:key="wifi enabled" 58 android:title="WiFi" /> 59 <PreferenceScreen 60 android:key="second_preferencescreen" 61 android:title="WiFi settings"> 62 <CheckBoxPreference 63 android:key="prefer wifi" 64 android:title="Prefer WiFi" /> 65 ... other preferences here ... 66 </PreferenceScreen> 67</PreferenceScreen> </pre> 68 * <p> 69 * In this example, the "first_preferencescreen" will be used as the root of the 70 * hierarchy and given to a {@link PreferenceActivity}. The first screen will 71 * show preferences "WiFi" (which can be used to quickly enable/disable WiFi) 72 * and "WiFi settings". The "WiFi settings" is the "second_preferencescreen" and when 73 * clicked will show another screen of preferences such as "Prefer WiFi" (and 74 * the other preferences that are children of the "second_preferencescreen" tag). 75 * 76 * @see PreferenceCategory 77 */ 78public final class PreferenceScreen extends PreferenceGroup implements AdapterView.OnItemClickListener, 79 DialogInterface.OnDismissListener { 80 81 private ListAdapter mRootAdapter; 82 83 private Dialog mDialog; 84 85 private ListView mListView; 86 87 /** 88 * Do NOT use this constructor, use {@link PreferenceManager#createPreferenceScreen(Context)}. 89 * @hide- 90 */ 91 public PreferenceScreen(Context context, AttributeSet attrs) { 92 super(context, attrs, com.android.internal.R.attr.preferenceScreenStyle); 93 } 94 95 /** 96 * Returns an adapter that can be attached to a {@link PreferenceActivity} 97 * or {@link PreferenceFragment} to show the preferences contained in this 98 * {@link PreferenceScreen}. 99 * <p> 100 * This {@link PreferenceScreen} will NOT appear in the returned adapter, instead 101 * it appears in the hierarchy above this {@link PreferenceScreen}. 102 * <p> 103 * This adapter's {@link Adapter#getItem(int)} should always return a 104 * subclass of {@link Preference}. 105 * 106 * @return An adapter that provides the {@link Preference} contained in this 107 * {@link PreferenceScreen}. 108 */ 109 public ListAdapter getRootAdapter() { 110 if (mRootAdapter == null) { 111 mRootAdapter = onCreateRootAdapter(); 112 } 113 114 return mRootAdapter; 115 } 116 117 /** 118 * Creates the root adapter. 119 * 120 * @return An adapter that contains the preferences contained in this {@link PreferenceScreen}. 121 * @see #getRootAdapter() 122 */ 123 protected ListAdapter onCreateRootAdapter() { 124 return new PreferenceGroupAdapter(this); 125 } 126 127 /** 128 * Binds a {@link ListView} to the preferences contained in this {@link PreferenceScreen} via 129 * {@link #getRootAdapter()}. It also handles passing list item clicks to the corresponding 130 * {@link Preference} contained by this {@link PreferenceScreen}. 131 * 132 * @param listView The list view to attach to. 133 */ 134 public void bind(ListView listView) { 135 listView.setOnItemClickListener(this); 136 listView.setAdapter(getRootAdapter()); 137 138 onAttachedToActivity(); 139 } 140 141 @Override 142 protected void onClick() { 143 if (getIntent() != null || getFragment() != null || getPreferenceCount() == 0) { 144 return; 145 } 146 147 showDialog(null); 148 } 149 150 private void showDialog(Bundle state) { 151 Context context = getContext(); 152 if (mListView != null) { 153 mListView.setAdapter(null); 154 } 155 mListView = new ListView(context); 156 bind(mListView); 157 158 // Set the title bar if title is available, else no title bar 159 final CharSequence title = getTitle(); 160 Dialog dialog = mDialog = new Dialog(context, context.getThemeResId()); 161 if (TextUtils.isEmpty(title)) { 162 dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); 163 } else { 164 dialog.setTitle(title); 165 } 166 dialog.setContentView(mListView); 167 dialog.setOnDismissListener(this); 168 if (state != null) { 169 dialog.onRestoreInstanceState(state); 170 } 171 172 // Add the screen to the list of preferences screens opened as dialogs 173 getPreferenceManager().addPreferencesScreen(dialog); 174 175 dialog.show(); 176 } 177 178 public void onDismiss(DialogInterface dialog) { 179 mDialog = null; 180 getPreferenceManager().removePreferencesScreen(dialog); 181 } 182 183 /** 184 * Used to get a handle to the dialog. 185 * This is useful for cases where we want to manipulate the dialog 186 * as we would with any other activity or view. 187 */ 188 public Dialog getDialog() { 189 return mDialog; 190 } 191 192 public void onItemClick(AdapterView parent, View view, int position, long id) { 193 Object item = getRootAdapter().getItem(position); 194 if (!(item instanceof Preference)) return; 195 196 final Preference preference = (Preference) item; 197 preference.performClick(this); 198 } 199 200 @Override 201 protected boolean isOnSameScreenAsChildren() { 202 return false; 203 } 204 205 @Override 206 protected Parcelable onSaveInstanceState() { 207 final Parcelable superState = super.onSaveInstanceState(); 208 final Dialog dialog = mDialog; 209 if (dialog == null || !dialog.isShowing()) { 210 return superState; 211 } 212 213 final SavedState myState = new SavedState(superState); 214 myState.isDialogShowing = true; 215 myState.dialogBundle = dialog.onSaveInstanceState(); 216 return myState; 217 } 218 219 @Override 220 protected void onRestoreInstanceState(Parcelable state) { 221 if (state == null || !state.getClass().equals(SavedState.class)) { 222 // Didn't save state for us in onSaveInstanceState 223 super.onRestoreInstanceState(state); 224 return; 225 } 226 227 SavedState myState = (SavedState) state; 228 super.onRestoreInstanceState(myState.getSuperState()); 229 if (myState.isDialogShowing) { 230 showDialog(myState.dialogBundle); 231 } 232 } 233 234 private static class SavedState extends BaseSavedState { 235 boolean isDialogShowing; 236 Bundle dialogBundle; 237 238 public SavedState(Parcel source) { 239 super(source); 240 isDialogShowing = source.readInt() == 1; 241 dialogBundle = source.readBundle(); 242 } 243 244 @Override 245 public void writeToParcel(Parcel dest, int flags) { 246 super.writeToParcel(dest, flags); 247 dest.writeInt(isDialogShowing ? 1 : 0); 248 dest.writeBundle(dialogBundle); 249 } 250 251 public SavedState(Parcelable superState) { 252 super(superState); 253 } 254 255 public static final Parcelable.Creator<SavedState> CREATOR = 256 new Parcelable.Creator<SavedState>() { 257 public SavedState createFromParcel(Parcel in) { 258 return new SavedState(in); 259 } 260 261 public SavedState[] newArray(int size) { 262 return new SavedState[size]; 263 } 264 }; 265 } 266 267} 268