blob: db806760fb680479e599695c12385ea5dd14a4f0 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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;
Amith Yamasanica74c902009-06-17 16:56:08 -070025import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.util.AttributeSet;
Amith Yamasanif9638a42012-04-30 16:32:39 -070027import android.view.LayoutInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.view.View;
Amith Yamasani72e6bec2011-09-23 10:43:40 -070029import android.view.Window;
Amith Yamasani2d43d282011-09-29 15:16:16 -070030import android.widget.AbsListView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.widget.Adapter;
32import android.widget.AdapterView;
33import android.widget.ListAdapter;
34import android.widget.ListView;
35
36/**
37 * Represents a top-level {@link Preference} that
38 * is the root of a Preference hierarchy. A {@link PreferenceActivity}
39 * points to an instance of this class to show the preferences. To instantiate
40 * this class, use {@link PreferenceManager#createPreferenceScreen(Context)}.
41 * <ul>
42 * This class can appear in two places:
43 * <li> When a {@link PreferenceActivity} points to this, it is used as the root
44 * and is not shown (only the contained preferences are shown).
45 * <li> When it appears inside another preference hierarchy, it is shown and
46 * serves as the gateway to another screen of preferences (either by showing
47 * another screen of preferences as a {@link Dialog} or via a
48 * {@link Context#startActivity(android.content.Intent)} from the
49 * {@link Preference#getIntent()}). The children of this {@link PreferenceScreen}
50 * are NOT shown in the screen that this {@link PreferenceScreen} is shown in.
51 * Instead, a separate screen will be shown when this preference is clicked.
52 * </ul>
53 * <p>Here's an example XML layout of a PreferenceScreen:</p>
54 * <pre>
55&lt;PreferenceScreen
56 xmlns:android="http://schemas.android.com/apk/res/android"
57 android:key="first_preferencescreen"&gt;
58 &lt;CheckBoxPreference
59 android:key="wifi enabled"
60 android:title="WiFi" /&gt;
61 &lt;PreferenceScreen
62 android:key="second_preferencescreen"
63 android:title="WiFi settings"&gt;
64 &lt;CheckBoxPreference
65 android:key="prefer wifi"
66 android:title="Prefer WiFi" /&gt;
67 ... other preferences here ...
68 &lt;/PreferenceScreen&gt;
69&lt;/PreferenceScreen&gt; </pre>
70 * <p>
71 * In this example, the "first_preferencescreen" will be used as the root of the
72 * hierarchy and given to a {@link PreferenceActivity}. The first screen will
73 * show preferences "WiFi" (which can be used to quickly enable/disable WiFi)
74 * and "WiFi settings". The "WiFi settings" is the "second_preferencescreen" and when
75 * clicked will show another screen of preferences such as "Prefer WiFi" (and
76 * the other preferences that are children of the "second_preferencescreen" tag).
77 *
Scott Maincdd0c592012-07-26 17:03:51 -070078 * <div class="special reference">
79 * <h3>Developer Guides</h3>
80 * <p>For information about building a settings UI with Preferences,
81 * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
82 * guide.</p>
83 * </div>
84 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 * @see PreferenceCategory
86 */
87public final class PreferenceScreen extends PreferenceGroup implements AdapterView.OnItemClickListener,
88 DialogInterface.OnDismissListener {
89
90 private ListAdapter mRootAdapter;
91
92 private Dialog mDialog;
Mathias Jeppsson15600032011-01-18 14:34:52 +010093
94 private ListView mListView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
96 /**
97 * Do NOT use this constructor, use {@link PreferenceManager#createPreferenceScreen(Context)}.
98 * @hide-
99 */
100 public PreferenceScreen(Context context, AttributeSet attrs) {
101 super(context, attrs, com.android.internal.R.attr.preferenceScreenStyle);
102 }
103
104 /**
105 * Returns an adapter that can be attached to a {@link PreferenceActivity}
Daisuke Miyakawa52a50782010-08-13 13:20:04 -0700106 * or {@link PreferenceFragment} to show the preferences contained in this
107 * {@link PreferenceScreen}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 * <p>
109 * This {@link PreferenceScreen} will NOT appear in the returned adapter, instead
110 * it appears in the hierarchy above this {@link PreferenceScreen}.
111 * <p>
112 * This adapter's {@link Adapter#getItem(int)} should always return a
113 * subclass of {@link Preference}.
114 *
115 * @return An adapter that provides the {@link Preference} contained in this
116 * {@link PreferenceScreen}.
117 */
118 public ListAdapter getRootAdapter() {
119 if (mRootAdapter == null) {
120 mRootAdapter = onCreateRootAdapter();
121 }
122
123 return mRootAdapter;
124 }
125
126 /**
127 * Creates the root adapter.
128 *
129 * @return An adapter that contains the preferences contained in this {@link PreferenceScreen}.
130 * @see #getRootAdapter()
131 */
132 protected ListAdapter onCreateRootAdapter() {
133 return new PreferenceGroupAdapter(this);
134 }
135
136 /**
137 * Binds a {@link ListView} to the preferences contained in this {@link PreferenceScreen} via
138 * {@link #getRootAdapter()}. It also handles passing list item clicks to the corresponding
139 * {@link Preference} contained by this {@link PreferenceScreen}.
140 *
141 * @param listView The list view to attach to.
142 */
143 public void bind(ListView listView) {
144 listView.setOnItemClickListener(this);
145 listView.setAdapter(getRootAdapter());
146
147 onAttachedToActivity();
148 }
149
150 @Override
151 protected void onClick() {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700152 if (getIntent() != null || getFragment() != null || getPreferenceCount() == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 return;
154 }
155
156 showDialog(null);
157 }
158
159 private void showDialog(Bundle state) {
160 Context context = getContext();
Mathias Jeppsson15600032011-01-18 14:34:52 +0100161 if (mListView != null) {
162 mListView.setAdapter(null);
163 }
Amith Yamasanif9638a42012-04-30 16:32:39 -0700164
165 LayoutInflater inflater = (LayoutInflater)
166 context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
167 View childPrefScreen = inflater.inflate(
168 com.android.internal.R.layout.preference_list_fragment, null);
169 mListView = (ListView) childPrefScreen.findViewById(android.R.id.list);
Mathias Jeppsson15600032011-01-18 14:34:52 +0100170 bind(mListView);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
Amith Yamasanica74c902009-06-17 16:56:08 -0700172 // Set the title bar if title is available, else no title bar
173 final CharSequence title = getTitle();
Amith Yamasani72e6bec2011-09-23 10:43:40 -0700174 Dialog dialog = mDialog = new Dialog(context, context.getThemeResId());
175 if (TextUtils.isEmpty(title)) {
176 dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
177 } else {
Amith Yamasanica74c902009-06-17 16:56:08 -0700178 dialog.setTitle(title);
179 }
Amith Yamasanif9638a42012-04-30 16:32:39 -0700180 dialog.setContentView(childPrefScreen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 dialog.setOnDismissListener(this);
182 if (state != null) {
183 dialog.onRestoreInstanceState(state);
184 }
Amith Yamasanica74c902009-06-17 16:56:08 -0700185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 // Add the screen to the list of preferences screens opened as dialogs
187 getPreferenceManager().addPreferencesScreen(dialog);
188
189 dialog.show();
190 }
191
192 public void onDismiss(DialogInterface dialog) {
193 mDialog = null;
194 getPreferenceManager().removePreferencesScreen(dialog);
195 }
196
197 /**
198 * Used to get a handle to the dialog.
199 * This is useful for cases where we want to manipulate the dialog
200 * as we would with any other activity or view.
201 */
202 public Dialog getDialog() {
203 return mDialog;
204 }
205
206 public void onItemClick(AdapterView parent, View view, int position, long id) {
Amith Yamasani2d43d282011-09-29 15:16:16 -0700207 // If the list has headers, subtract them from the index.
208 if (parent instanceof ListView) {
209 position -= ((ListView) parent).getHeaderViewsCount();
210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 Object item = getRootAdapter().getItem(position);
212 if (!(item instanceof Preference)) return;
Amith Yamasani2d43d282011-09-29 15:16:16 -0700213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 final Preference preference = (Preference) item;
215 preference.performClick(this);
216 }
217
218 @Override
219 protected boolean isOnSameScreenAsChildren() {
220 return false;
221 }
222
223 @Override
224 protected Parcelable onSaveInstanceState() {
225 final Parcelable superState = super.onSaveInstanceState();
226 final Dialog dialog = mDialog;
227 if (dialog == null || !dialog.isShowing()) {
228 return superState;
229 }
230
231 final SavedState myState = new SavedState(superState);
232 myState.isDialogShowing = true;
233 myState.dialogBundle = dialog.onSaveInstanceState();
234 return myState;
235 }
236
237 @Override
238 protected void onRestoreInstanceState(Parcelable state) {
239 if (state == null || !state.getClass().equals(SavedState.class)) {
240 // Didn't save state for us in onSaveInstanceState
241 super.onRestoreInstanceState(state);
242 return;
243 }
244
245 SavedState myState = (SavedState) state;
246 super.onRestoreInstanceState(myState.getSuperState());
247 if (myState.isDialogShowing) {
248 showDialog(myState.dialogBundle);
249 }
250 }
251
252 private static class SavedState extends BaseSavedState {
253 boolean isDialogShowing;
254 Bundle dialogBundle;
255
256 public SavedState(Parcel source) {
257 super(source);
258 isDialogShowing = source.readInt() == 1;
259 dialogBundle = source.readBundle();
260 }
261
262 @Override
263 public void writeToParcel(Parcel dest, int flags) {
264 super.writeToParcel(dest, flags);
265 dest.writeInt(isDialogShowing ? 1 : 0);
266 dest.writeBundle(dialogBundle);
267 }
268
269 public SavedState(Parcelable superState) {
270 super(superState);
271 }
272
273 public static final Parcelable.Creator<SavedState> CREATOR =
274 new Parcelable.Creator<SavedState>() {
275 public SavedState createFromParcel(Parcel in) {
276 return new SavedState(in);
277 }
278
279 public SavedState[] newArray(int size) {
280 return new SavedState[size];
281 }
282 };
283 }
284
285}