blob: ad0bc84a40817382551cd174c82633f4bf946d84 [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
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070019import com.android.internal.util.XmlUtils;
20
21import org.xmlpull.v1.XmlPullParser;
22import org.xmlpull.v1.XmlPullParserException;
23
Jim Millerc57406c2010-12-08 16:01:05 -080024import android.app.ActionBar;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070025import android.app.Fragment;
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070026import android.app.FragmentBreadCrumbs;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -080027import android.app.FragmentManager;
Andrew Stadleraa904f42010-09-02 14:50:08 -070028import android.app.FragmentTransaction;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.app.ListActivity;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070030import android.content.Context;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.content.Intent;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070032import android.content.res.Configuration;
Dianne Hackborn50ed8292010-12-03 12:30:21 -080033import android.content.res.Resources;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070034import android.content.res.TypedArray;
35import android.content.res.XmlResourceParser;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.os.Bundle;
37import android.os.Handler;
38import android.os.Message;
Dianne Hackborna21e3da2010-09-12 19:27:46 -070039import android.os.Parcel;
40import android.os.Parcelable;
Freeman Ng19ea2e02010-03-25 15:09:00 -070041import android.text.TextUtils;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070042import android.util.AttributeSet;
Dianne Hackborn50ed8292010-12-03 12:30:21 -080043import android.util.TypedValue;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070044import android.util.Xml;
45import android.view.LayoutInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.view.View;
Freeman Ng19ea2e02010-03-25 15:09:00 -070047import android.view.View.OnClickListener;
Andrew Stadleraa904f42010-09-02 14:50:08 -070048import android.view.ViewGroup;
Dianne Hackborna21e3da2010-09-12 19:27:46 -070049import android.widget.AbsListView;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070050import android.widget.ArrayAdapter;
Freeman Ng19ea2e02010-03-25 15:09:00 -070051import android.widget.Button;
Dianne Hackborn5c769a42010-08-26 17:08:08 -070052import android.widget.FrameLayout;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070053import android.widget.ImageView;
54import android.widget.ListView;
55import android.widget.TextView;
56
57import java.io.IOException;
58import java.util.ArrayList;
59import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060
61/**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070062 * This is the base class for an activity to show a hierarchy of preferences
63 * to the user. Prior to {@link android.os.Build.VERSION_CODES#HONEYCOMB}
64 * this class only allowed the display of a single set of preference; this
65 * functionality should now be found in the new {@link PreferenceFragment}
66 * class. If you are using PreferenceActivity in its old mode, the documentation
67 * there applies to the deprecated APIs here.
Freeman Ng19ea2e02010-03-25 15:09:00 -070068 *
Dianne Hackbornb1ad5972010-08-02 17:30:33 -070069 * <p>This activity shows one or more headers of preferences, each of with
70 * is associated with a {@link PreferenceFragment} to display the preferences
71 * of that header. The actual layout and display of these associations can
72 * however vary; currently there are two major approaches it may take:
73 *
74 * <ul>
75 * <li>On a small screen it may display only the headers as a single list
76 * when first launched. Selecting one of the header items will re-launch
77 * the activity with it only showing the PreferenceFragment of that header.
78 * <li>On a large screen in may display both the headers and current
79 * PreferenceFragment together as panes. Selecting a header item switches
80 * to showing the correct PreferenceFragment for that item.
81 * </ul>
82 *
83 * <p>Subclasses of PreferenceActivity should implement
84 * {@link #onBuildHeaders} to populate the header list with the desired
85 * items. Doing this implicitly switches the class into its new "headers
86 * + fragments" mode rather than the old style of just showing a single
87 * preferences list.
88 *
89 * <a name="SampleCode"></a>
90 * <h3>Sample Code</h3>
91 *
92 * <p>The following sample code shows a simple preference activity that
93 * has two different sets of preferences. The implementation, consisting
94 * of the activity itself as well as its two preference fragments is:</p>
95 *
96 * {@sample development/samples/ApiDemos/src/com/example/android/apis/preference/PreferenceWithHeaders.java
97 * activity}
98 *
99 * <p>The preference_headers resource describes the headers to be displayed
100 * and the fragments associated with them. It is:
101 *
102 * {@sample development/samples/ApiDemos/res/xml/preference_headers.xml headers}
103 *
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700104 * <p>The first header is shown by Prefs1Fragment, which populates itself
105 * from the following XML resource:</p>
106 *
107 * {@sample development/samples/ApiDemos/res/xml/fragmented_preferences.xml preferences}
108 *
109 * <p>Note that this XML resource contains a preference screen holding another
110 * fragment, the Prefs1FragmentInner implemented here. This allows the user
111 * to traverse down a hierarchy of preferences; pressing back will pop each
112 * fragment off the stack to return to the previous preferences.
113 *
114 * <p>See {@link PreferenceFragment} for information on implementing the
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700115 * fragments themselves.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 */
117public abstract class PreferenceActivity extends ListActivity implements
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700118 PreferenceManager.OnPreferenceTreeClickListener,
119 PreferenceFragment.OnPreferenceStartFragmentCallback {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700120 private static final String TAG = "PreferenceActivity";
Freeman Ng19ea2e02010-03-25 15:09:00 -0700121
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700122 // Constants for state save/restore
123 private static final String HEADERS_TAG = ":android:headers";
124 private static final String CUR_HEADER_TAG = ":android:cur_header";
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700125 private static final String PREFERENCES_TAG = ":android:preferences";
Freeman Ng19ea2e02010-03-25 15:09:00 -0700126
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700127 /**
128 * When starting this activity, the invoking Intent can contain this extra
129 * string to specify which fragment should be initially displayed.
130 */
131 public static final String EXTRA_SHOW_FRAGMENT = ":android:show_fragment";
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700132
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700133 /**
134 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
135 * this extra can also be specify to supply a Bundle of arguments to pass
136 * to that fragment when it is instantiated during the initial creation
137 * of PreferenceActivity.
138 */
139 public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":android:show_fragment_args";
140
141 /**
142 * When starting this activity, the invoking Intent can contain this extra
143 * boolean that the header list should not be displayed. This is most often
144 * used in conjunction with {@link #EXTRA_SHOW_FRAGMENT} to launch
145 * the activity to display a specific fragment that the user has navigated
146 * to.
147 */
148 public static final String EXTRA_NO_HEADERS = ":android:no_headers";
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700149
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700150 private static final String BACK_STACK_PREFS = ":android:prefs";
151
Freeman Ng19ea2e02010-03-25 15:09:00 -0700152 // extras that allow any preference activity to be launched as part of a wizard
153
154 // show Back and Next buttons? takes boolean parameter
155 // Back will then return RESULT_CANCELED and Next RESULT_OK
156 private static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
157
Freeman Ng09dbf182010-08-11 15:45:01 -0700158 // add a Skip button?
159 private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip";
160
Freeman Ng19ea2e02010-03-25 15:09:00 -0700161 // specify custom text for the Back or Next buttons, or cause a button to not appear
162 // at all by setting it to null
163 private static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
164 private static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
165
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700166 // --- State for new mode when showing a list of headers + prefs fragment
167
168 private final ArrayList<Header> mHeaders = new ArrayList<Header>();
169
170 private HeaderAdapter mAdapter;
171
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700172 private FrameLayout mListFooter;
173
Amith Yamasani3c9f5192010-12-08 16:48:31 -0800174 private ViewGroup mPrefsContainer;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700175
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700176 private FragmentBreadCrumbs mFragmentBreadCrumbs;
177
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700178 private boolean mSinglePane;
179
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700180 private Header mCurHeader;
181
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700182 // --- State for old mode when showing a single preference list
Freeman Ng19ea2e02010-03-25 15:09:00 -0700183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 private PreferenceManager mPreferenceManager;
Freeman Ng19ea2e02010-03-25 15:09:00 -0700185
Adam Powelle7fea452010-03-18 14:51:39 -0700186 private Bundle mSavedInstanceState;
187
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700188 // --- Common state
189
190 private Button mNextButton;
191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 /**
193 * The starting request code given out to preference framework.
194 */
195 private static final int FIRST_REQUEST_CODE = 100;
Freeman Ng19ea2e02010-03-25 15:09:00 -0700196
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700197 private static final int MSG_BIND_PREFERENCES = 1;
198 private static final int MSG_BUILD_HEADERS = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 private Handler mHandler = new Handler() {
200 @Override
201 public void handleMessage(Message msg) {
202 switch (msg.what) {
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700203 case MSG_BIND_PREFERENCES: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 bindPreferences();
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700205 } break;
206 case MSG_BUILD_HEADERS: {
207 ArrayList<Header> oldHeaders = new ArrayList<Header>(mHeaders);
208 mHeaders.clear();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700209 onBuildHeaders(mHeaders);
Andrew Stadler83681eb2010-11-04 15:49:05 -0700210 if (mAdapter != null) {
211 mAdapter.notifyDataSetChanged();
212 }
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700213 Header header = onGetNewHeader();
214 if (header != null && header.fragment != null) {
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700215 Header mappedHeader = findBestMatchingHeader(header, oldHeaders);
216 if (mappedHeader == null || mCurHeader != mappedHeader) {
217 switchToHeader(header);
218 }
219 } else if (mCurHeader != null) {
220 Header mappedHeader = findBestMatchingHeader(mCurHeader, mHeaders);
221 if (mappedHeader != null) {
222 setSelectedHeader(mappedHeader);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700223 }
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700224 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700225 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 }
227 }
228 };
229
Andrew Stadler468c3232010-08-17 16:16:42 -0700230 private static class HeaderAdapter extends ArrayAdapter<Header> {
231 private static class HeaderViewHolder {
232 ImageView icon;
233 TextView title;
234 TextView summary;
235 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700236
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700237 private LayoutInflater mInflater;
238
239 public HeaderAdapter(Context context, List<Header> objects) {
240 super(context, 0, objects);
241 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
242 }
243
244 @Override
245 public View getView(int position, View convertView, ViewGroup parent) {
246 HeaderViewHolder holder;
247 View view;
248
249 if (convertView == null) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -0700250 view = mInflater.inflate(com.android.internal.R.layout.preference_header_item,
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700251 parent, false);
252 holder = new HeaderViewHolder();
Andrew Stadler468c3232010-08-17 16:16:42 -0700253 holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
254 holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
255 holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700256 view.setTag(holder);
257 } else {
258 view = convertView;
Andrew Stadler468c3232010-08-17 16:16:42 -0700259 holder = (HeaderViewHolder) view.getTag();
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700260 }
261
Andrew Stadler468c3232010-08-17 16:16:42 -0700262 // All view fields must be updated every time, because the view may be recycled
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700263 Header header = getItem(position);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700264 holder.icon.setImageResource(header.iconRes);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800265 holder.title.setText(header.getTitle(getContext().getResources()));
266 CharSequence summary = header.getSummary(getContext().getResources());
267 if (!TextUtils.isEmpty(summary)) {
Andrew Stadler468c3232010-08-17 16:16:42 -0700268 holder.summary.setVisibility(View.VISIBLE);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800269 holder.summary.setText(summary);
270 } else {
271 holder.summary.setVisibility(View.GONE);
Andrew Stadler468c3232010-08-17 16:16:42 -0700272 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700273
274 return view;
275 }
276 }
277
278 /**
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700279 * Default value for {@link Header#id Header.id} indicating that no
280 * identifier value is set. All other values (including those below -1)
281 * are valid.
282 */
283 public static final long HEADER_ID_UNDEFINED = -1;
284
285 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700286 * Description of a single Header item that the user can select.
287 */
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700288 public static final class Header implements Parcelable {
289 /**
290 * Identifier for this header, to correlate with a new list when
291 * it is updated. The default value is
292 * {@link PreferenceActivity#HEADER_ID_UNDEFINED}, meaning no id.
293 * @attr ref android.R.styleable#PreferenceHeader_id
294 */
295 public long id = HEADER_ID_UNDEFINED;
296
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700297 /**
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800298 * Resource ID of title of the header that is shown to the user.
299 * @attr ref android.R.styleable#PreferenceHeader_title
300 */
301 public int titleRes;
302
303 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700304 * Title of the header that is shown to the user.
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700305 * @attr ref android.R.styleable#PreferenceHeader_title
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700306 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700307 public CharSequence title;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700308
309 /**
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800310 * Resource ID of optional summary describing what this header controls.
311 * @attr ref android.R.styleable#PreferenceHeader_summary
312 */
313 public int summaryRes;
314
315 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700316 * Optional summary describing what this header controls.
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700317 * @attr ref android.R.styleable#PreferenceHeader_summary
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700318 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700319 public CharSequence summary;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700320
321 /**
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800322 * Resource ID of optional text to show as the title in the bread crumb.
323 * @attr ref android.R.styleable#PreferenceHeader_breadCrumbTitle
324 */
325 public int breadCrumbTitleRes;
326
327 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700328 * Optional text to show as the title in the bread crumb.
329 * @attr ref android.R.styleable#PreferenceHeader_breadCrumbTitle
330 */
331 public CharSequence breadCrumbTitle;
332
333 /**
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800334 * Resource ID of optional text to show as the short title in the bread crumb.
335 * @attr ref android.R.styleable#PreferenceHeader_breadCrumbShortTitle
336 */
337 public int breadCrumbShortTitleRes;
338
339 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700340 * Optional text to show as the short title in the bread crumb.
341 * @attr ref android.R.styleable#PreferenceHeader_breadCrumbShortTitle
342 */
343 public CharSequence breadCrumbShortTitle;
344
345 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700346 * Optional icon resource to show for this header.
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700347 * @attr ref android.R.styleable#PreferenceHeader_icon
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700348 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700349 public int iconRes;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700350
351 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700352 * Full class name of the fragment to display when this header is
353 * selected.
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700354 * @attr ref android.R.styleable#PreferenceHeader_fragment
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700355 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700356 public String fragment;
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700357
358 /**
359 * Optional arguments to supply to the fragment when it is
360 * instantiated.
361 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700362 public Bundle fragmentArguments;
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700363
364 /**
365 * Intent to launch when the preference is selected.
366 */
367 public Intent intent;
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700368
369 /**
370 * Optional additional data for use by subclasses of PreferenceActivity.
371 */
372 public Bundle extras;
373
374 public Header() {
375 }
376
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800377 /**
378 * Return the currently set title. If {@link #titleRes} is set,
379 * this resource is loaded from <var>res</var> and returned. Otherwise
380 * {@link #title} is returned.
381 */
382 public CharSequence getTitle(Resources res) {
383 if (titleRes != 0) {
384 return res.getText(titleRes);
385 }
386 return title;
387 }
388
389 /**
390 * Return the currently set summary. If {@link #summaryRes} is set,
391 * this resource is loaded from <var>res</var> and returned. Otherwise
392 * {@link #summary} is returned.
393 */
394 public CharSequence getSummary(Resources res) {
395 if (summaryRes != 0) {
396 return res.getText(summaryRes);
397 }
Dianne Hackborn9d071802010-12-08 14:49:15 -0800398 return summary;
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800399 }
400
401 /**
402 * Return the currently set bread crumb title. If {@link #breadCrumbTitleRes} is set,
403 * this resource is loaded from <var>res</var> and returned. Otherwise
404 * {@link #breadCrumbTitle} is returned.
405 */
406 public CharSequence getBreadCrumbTitle(Resources res) {
407 if (breadCrumbTitleRes != 0) {
408 return res.getText(breadCrumbTitleRes);
409 }
410 return breadCrumbTitle;
411 }
412
413 /**
414 * Return the currently set bread crumb short title. If
415 * {@link #breadCrumbShortTitleRes} is set,
416 * this resource is loaded from <var>res</var> and returned. Otherwise
417 * {@link #breadCrumbShortTitle} is returned.
418 */
419 public CharSequence getBreadCrumbShortTitle(Resources res) {
420 if (breadCrumbShortTitleRes != 0) {
421 return res.getText(breadCrumbShortTitleRes);
422 }
423 return breadCrumbShortTitle;
424 }
425
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700426 @Override
427 public int describeContents() {
428 return 0;
429 }
430
431 @Override
432 public void writeToParcel(Parcel dest, int flags) {
433 dest.writeLong(id);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800434 dest.writeInt(titleRes);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700435 TextUtils.writeToParcel(title, dest, flags);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800436 dest.writeInt(summaryRes);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700437 TextUtils.writeToParcel(summary, dest, flags);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800438 dest.writeInt(breadCrumbTitleRes);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700439 TextUtils.writeToParcel(breadCrumbTitle, dest, flags);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800440 dest.writeInt(breadCrumbShortTitleRes);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700441 TextUtils.writeToParcel(breadCrumbShortTitle, dest, flags);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700442 dest.writeInt(iconRes);
443 dest.writeString(fragment);
444 dest.writeBundle(fragmentArguments);
445 if (intent != null) {
446 dest.writeInt(1);
447 intent.writeToParcel(dest, flags);
448 } else {
449 dest.writeInt(0);
450 }
451 dest.writeBundle(extras);
452 }
453
454 public void readFromParcel(Parcel in) {
455 id = in.readLong();
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800456 titleRes = in.readInt();
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700457 title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800458 summaryRes = in.readInt();
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700459 summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800460 breadCrumbTitleRes = in.readInt();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700461 breadCrumbTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800462 breadCrumbShortTitleRes = in.readInt();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700463 breadCrumbShortTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700464 iconRes = in.readInt();
465 fragment = in.readString();
466 fragmentArguments = in.readBundle();
467 if (in.readInt() != 0) {
468 intent = Intent.CREATOR.createFromParcel(in);
469 }
470 extras = in.readBundle();
471 }
472
473 Header(Parcel in) {
474 readFromParcel(in);
475 }
476
477 public static final Creator<Header> CREATOR = new Creator<Header>() {
478 public Header createFromParcel(Parcel source) {
479 return new Header(source);
480 }
481 public Header[] newArray(int size) {
482 return new Header[size];
483 }
484 };
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700485 }
486
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 @Override
488 protected void onCreate(Bundle savedInstanceState) {
489 super.onCreate(savedInstanceState);
490
491 setContentView(com.android.internal.R.layout.preference_list_content);
Freeman Ng19ea2e02010-03-25 15:09:00 -0700492
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700493 mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer);
Amith Yamasani3c9f5192010-12-08 16:48:31 -0800494 mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs_frame);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700495 boolean hidingHeaders = onIsHidingHeaders();
496 mSinglePane = hidingHeaders || !onIsMultiPane();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700497 String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
498 Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700499
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700500 if (savedInstanceState != null) {
501 // We are restarting from a previous saved state; used that to
502 // initialize, instead of starting fresh.
503 ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG);
504 if (headers != null) {
505 mHeaders.addAll(headers);
506 int curHeader = savedInstanceState.getInt(CUR_HEADER_TAG,
507 (int)HEADER_ID_UNDEFINED);
508 if (curHeader >= 0 && curHeader < mHeaders.size()) {
509 setSelectedHeader(mHeaders.get(curHeader));
510 }
511 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700512
513 } else {
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700514 if (initialFragment != null && mSinglePane) {
515 // If we are just showing a fragment, we want to run in
516 // new fragment mode, but don't need to compute and show
517 // the headers.
518 switchToHeader(initialFragment, initialArguments);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700519
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700520 } else {
521 // We need to try to build the headers.
522 onBuildHeaders(mHeaders);
523
524 // If there are headers, then at this point we need to show
525 // them and, depending on the screen, we may also show in-line
526 // the currently selected preference fragment.
527 if (mHeaders.size() > 0) {
528 if (!mSinglePane) {
529 if (initialFragment == null) {
530 Header h = onGetInitialHeader();
531 switchToHeader(h);
532 } else {
533 switchToHeader(initialFragment, initialArguments);
534 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700535 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700536 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700537 }
538 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700539
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700540 // The default configuration is to only show the list view. Adjust
541 // visibility for other configurations.
542 if (initialFragment != null && mSinglePane) {
543 // Single pane, showing just a prefs fragment.
Amith Yamasani05fbc312010-09-26 13:29:01 -0700544 findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700545 mPrefsContainer.setVisibility(View.VISIBLE);
546 } else if (mHeaders.size() > 0) {
547 mAdapter = new HeaderAdapter(this, mHeaders);
548 setListAdapter(mAdapter);
549 if (!mSinglePane) {
550 // Multi-pane.
551 getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
Dianne Hackbornd0fa3712010-09-14 18:57:14 -0700552 if (mCurHeader != null) {
553 setSelectedHeader(mCurHeader);
554 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700555 mPrefsContainer.setVisibility(View.VISIBLE);
556 }
557 } else {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700558 // If there are no headers, we are in the old "just show a screen
559 // of preferences" mode.
Amith Yamasani8da35292010-11-05 09:15:51 -0700560 setContentView(com.android.internal.R.layout.preference_list_content_single);
561 mListFooter = (FrameLayout) findViewById(com.android.internal.R.id.list_footer);
Amith Yamasani3c9f5192010-12-08 16:48:31 -0800562 mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700563 mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
564 mPreferenceManager.setOnPreferenceTreeClickListener(this);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700565 }
566
567 getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
568
Freeman Ng19ea2e02010-03-25 15:09:00 -0700569 // see if we should show Back/Next buttons
570 Intent intent = getIntent();
571 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
572
573 findViewById(com.android.internal.R.id.button_bar).setVisibility(View.VISIBLE);
574
575 Button backButton = (Button)findViewById(com.android.internal.R.id.back_button);
576 backButton.setOnClickListener(new OnClickListener() {
577 public void onClick(View v) {
578 setResult(RESULT_CANCELED);
579 finish();
580 }
581 });
Freeman Ng09dbf182010-08-11 15:45:01 -0700582 Button skipButton = (Button)findViewById(com.android.internal.R.id.skip_button);
583 skipButton.setOnClickListener(new OnClickListener() {
584 public void onClick(View v) {
585 setResult(RESULT_OK);
586 finish();
587 }
588 });
Freeman Ng19ea2e02010-03-25 15:09:00 -0700589 mNextButton = (Button)findViewById(com.android.internal.R.id.next_button);
590 mNextButton.setOnClickListener(new OnClickListener() {
591 public void onClick(View v) {
592 setResult(RESULT_OK);
593 finish();
594 }
595 });
596
597 // set our various button parameters
598 if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
599 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
600 if (TextUtils.isEmpty(buttonText)) {
601 mNextButton.setVisibility(View.GONE);
602 }
603 else {
604 mNextButton.setText(buttonText);
605 }
606 }
607 if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
608 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
609 if (TextUtils.isEmpty(buttonText)) {
610 backButton.setVisibility(View.GONE);
611 }
612 else {
613 backButton.setText(buttonText);
614 }
615 }
Freeman Ng09dbf182010-08-11 15:45:01 -0700616 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
617 skipButton.setVisibility(View.VISIBLE);
618 }
Freeman Ng19ea2e02010-03-25 15:09:00 -0700619 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700620 }
Freeman Ng19ea2e02010-03-25 15:09:00 -0700621
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700622 /**
Dianne Hackborn291905e2010-08-17 15:17:15 -0700623 * Returns true if this activity is currently showing the header list.
624 */
625 public boolean hasHeaders() {
626 return getListView().getVisibility() == View.VISIBLE
627 && mPreferenceManager == null;
628 }
629
630 /**
631 * Returns true if this activity is showing multiple panes -- the headers
632 * and a preference fragment.
633 */
634 public boolean isMultiPane() {
635 return hasHeaders() && mPrefsContainer.getVisibility() == View.VISIBLE;
636 }
637
638 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700639 * Called to determine if the activity should run in multi-pane mode.
640 * The default implementation returns true if the screen is large
641 * enough.
642 */
643 public boolean onIsMultiPane() {
644 Configuration config = getResources().getConfiguration();
645 if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700646 == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
647 return true;
648 }
649 if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
650 == Configuration.SCREENLAYOUT_SIZE_LARGE
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700651 && config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
652 return true;
653 }
654 return false;
655 }
656
657 /**
Dianne Hackborn291905e2010-08-17 15:17:15 -0700658 * Called to determine whether the header list should be hidden.
659 * The default implementation returns the
660 * value given in {@link #EXTRA_NO_HEADERS} or false if it is not supplied.
661 * This is set to false, for example, when the activity is being re-launched
662 * to show a particular preference activity.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700663 */
664 public boolean onIsHidingHeaders() {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700665 return getIntent().getBooleanExtra(EXTRA_NO_HEADERS, false);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700666 }
667
668 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700669 * Called to determine the initial header to be shown. The default
670 * implementation simply returns the fragment of the first header. Note
671 * that the returned Header object does not actually need to exist in
672 * your header list -- whatever its fragment is will simply be used to
673 * show for the initial UI.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700674 */
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700675 public Header onGetInitialHeader() {
676 return mHeaders.get(0);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700677 }
678
679 /**
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700680 * Called after the header list has been updated ({@link #onBuildHeaders}
681 * has been called and returned due to {@link #invalidateHeaders()}) to
682 * specify the header that should now be selected. The default implementation
683 * returns null to keep whatever header is currently selected.
684 */
685 public Header onGetNewHeader() {
686 return null;
687 }
688
689 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700690 * Called when the activity needs its list of headers build. By
691 * implementing this and adding at least one item to the list, you
692 * will cause the activity to run in its modern fragment mode. Note
693 * that this function may not always be called; for example, if the
694 * activity has been asked to display a particular fragment without
695 * the header list, there is no need to build the headers.
696 *
697 * <p>Typical implementations will use {@link #loadHeadersFromResource}
698 * to fill in the list from a resource.
699 *
700 * @param target The list in which to place the headers.
701 */
702 public void onBuildHeaders(List<Header> target) {
703 }
704
705 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700706 * Call when you need to change the headers being displayed. Will result
707 * in onBuildHeaders() later being called to retrieve the new list.
708 */
709 public void invalidateHeaders() {
710 if (!mHandler.hasMessages(MSG_BUILD_HEADERS)) {
711 mHandler.sendEmptyMessage(MSG_BUILD_HEADERS);
712 }
713 }
714
715 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700716 * Parse the given XML file as a header description, adding each
717 * parsed Header into the target list.
718 *
719 * @param resid The XML resource to load and parse.
720 * @param target The list in which the parsed headers should be placed.
721 */
722 public void loadHeadersFromResource(int resid, List<Header> target) {
723 XmlResourceParser parser = null;
724 try {
725 parser = getResources().getXml(resid);
726 AttributeSet attrs = Xml.asAttributeSet(parser);
727
728 int type;
729 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
730 && type != XmlPullParser.START_TAG) {
731 }
732
733 String nodeName = parser.getName();
Dianne Hackborndef15372010-08-15 12:43:52 -0700734 if (!"preference-headers".equals(nodeName)) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700735 throw new RuntimeException(
Dianne Hackborndef15372010-08-15 12:43:52 -0700736 "XML document must start with <preference-headers> tag; found"
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700737 + nodeName + " at " + parser.getPositionDescription());
738 }
739
Dianne Hackborndef15372010-08-15 12:43:52 -0700740 Bundle curBundle = null;
741
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700742 final int outerDepth = parser.getDepth();
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700743 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
744 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
745 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
746 continue;
747 }
748
749 nodeName = parser.getName();
Dianne Hackborndef15372010-08-15 12:43:52 -0700750 if ("header".equals(nodeName)) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700751 Header header = new Header();
752
753 TypedArray sa = getResources().obtainAttributes(attrs,
754 com.android.internal.R.styleable.PreferenceHeader);
Amith Yamasanied13cde2010-09-17 16:56:47 -0700755 header.id = sa.getResourceId(
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700756 com.android.internal.R.styleable.PreferenceHeader_id,
757 (int)HEADER_ID_UNDEFINED);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800758 TypedValue tv = sa.peekValue(
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700759 com.android.internal.R.styleable.PreferenceHeader_title);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800760 if (tv != null && tv.type == TypedValue.TYPE_STRING) {
761 if (tv.resourceId != 0) {
762 header.titleRes = tv.resourceId;
763 } else {
764 header.title = tv.string;
765 }
766 }
767 tv = sa.peekValue(
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700768 com.android.internal.R.styleable.PreferenceHeader_summary);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800769 if (tv != null && tv.type == TypedValue.TYPE_STRING) {
770 if (tv.resourceId != 0) {
771 header.summaryRes = tv.resourceId;
772 } else {
773 header.summary = tv.string;
774 }
775 }
776 tv = sa.peekValue(
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700777 com.android.internal.R.styleable.PreferenceHeader_breadCrumbTitle);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800778 if (tv != null && tv.type == TypedValue.TYPE_STRING) {
779 if (tv.resourceId != 0) {
780 header.breadCrumbTitleRes = tv.resourceId;
781 } else {
782 header.breadCrumbTitle = tv.string;
783 }
784 }
785 tv = sa.peekValue(
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700786 com.android.internal.R.styleable.PreferenceHeader_breadCrumbShortTitle);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800787 if (tv != null && tv.type == TypedValue.TYPE_STRING) {
788 if (tv.resourceId != 0) {
789 header.breadCrumbShortTitleRes = tv.resourceId;
790 } else {
791 header.breadCrumbShortTitle = tv.string;
792 }
793 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700794 header.iconRes = sa.getResourceId(
795 com.android.internal.R.styleable.PreferenceHeader_icon, 0);
796 header.fragment = sa.getString(
797 com.android.internal.R.styleable.PreferenceHeader_fragment);
798 sa.recycle();
799
Dianne Hackborndef15372010-08-15 12:43:52 -0700800 if (curBundle == null) {
801 curBundle = new Bundle();
802 }
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700803
804 final int innerDepth = parser.getDepth();
805 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
806 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
807 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
808 continue;
809 }
810
811 String innerNodeName = parser.getName();
812 if (innerNodeName.equals("extra")) {
813 getResources().parseBundleExtra("extra", attrs, curBundle);
814 XmlUtils.skipCurrentTag(parser);
815
816 } else if (innerNodeName.equals("intent")) {
817 header.intent = Intent.parseIntent(getResources(), parser, attrs);
818
819 } else {
820 XmlUtils.skipCurrentTag(parser);
821 }
822 }
823
Dianne Hackborndef15372010-08-15 12:43:52 -0700824 if (curBundle.size() > 0) {
825 header.fragmentArguments = curBundle;
826 curBundle = null;
827 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700828
Dianne Hackborndef15372010-08-15 12:43:52 -0700829 target.add(header);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700830 } else {
831 XmlUtils.skipCurrentTag(parser);
832 }
833 }
834
835 } catch (XmlPullParserException e) {
836 throw new RuntimeException("Error parsing headers", e);
837 } catch (IOException e) {
838 throw new RuntimeException("Error parsing headers", e);
839 } finally {
840 if (parser != null) parser.close();
841 }
842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 }
844
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700845 /**
846 * Set a footer that should be shown at the bottom of the header list.
847 */
848 public void setListFooter(View view) {
849 mListFooter.removeAllViews();
850 mListFooter.addView(view, new FrameLayout.LayoutParams(
851 FrameLayout.LayoutParams.MATCH_PARENT,
852 FrameLayout.LayoutParams.WRAP_CONTENT));
853 }
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 @Override
856 protected void onStop() {
857 super.onStop();
Freeman Ng19ea2e02010-03-25 15:09:00 -0700858
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700859 if (mPreferenceManager != null) {
860 mPreferenceManager.dispatchActivityStop();
861 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 }
863
864 @Override
865 protected void onDestroy() {
866 super.onDestroy();
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700867
868 if (mPreferenceManager != null) {
869 mPreferenceManager.dispatchActivityDestroy();
870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 }
872
873 @Override
874 protected void onSaveInstanceState(Bundle outState) {
875 super.onSaveInstanceState(outState);
876
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700877 if (mHeaders.size() > 0) {
878 outState.putParcelableArrayList(HEADERS_TAG, mHeaders);
879 if (mCurHeader != null) {
880 int index = mHeaders.indexOf(mCurHeader);
881 if (index >= 0) {
882 outState.putInt(CUR_HEADER_TAG, index);
883 }
884 }
885 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700886
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700887 if (mPreferenceManager != null) {
888 final PreferenceScreen preferenceScreen = getPreferenceScreen();
889 if (preferenceScreen != null) {
890 Bundle container = new Bundle();
891 preferenceScreen.saveHierarchyState(container);
892 outState.putBundle(PREFERENCES_TAG, container);
893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 }
895 }
896
897 @Override
898 protected void onRestoreInstanceState(Bundle state) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700899 if (mPreferenceManager != null) {
900 Bundle container = state.getBundle(PREFERENCES_TAG);
901 if (container != null) {
902 final PreferenceScreen preferenceScreen = getPreferenceScreen();
903 if (preferenceScreen != null) {
904 preferenceScreen.restoreHierarchyState(container);
905 mSavedInstanceState = state;
906 return;
907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 }
909 }
Adam Powelle7fea452010-03-18 14:51:39 -0700910
911 // Only call this if we didn't save the instance state for later.
912 // If we did save it, it will be restored when we bind the adapter.
913 super.onRestoreInstanceState(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 }
915
916 @Override
917 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
918 super.onActivityResult(requestCode, resultCode, data);
Freeman Ng19ea2e02010-03-25 15:09:00 -0700919
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700920 if (mPreferenceManager != null) {
921 mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 }
924
925 @Override
926 public void onContentChanged() {
927 super.onContentChanged();
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700928
929 if (mPreferenceManager != null) {
930 postBindPreferences();
931 }
932 }
933
934 @Override
935 protected void onListItemClick(ListView l, View v, int position, long id) {
936 super.onListItemClick(l, v, position, id);
937
938 if (mAdapter != null) {
939 onHeaderClick(mHeaders.get(position), position);
940 }
941 }
942
943 /**
944 * Called when the user selects an item in the header list. The default
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700945 * implementation will call either {@link #startWithFragment(String, Bundle, Fragment, int)}
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700946 * or {@link #switchToHeader(Header)} as appropriate.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700947 *
948 * @param header The header that was selected.
949 * @param position The header's position in the list.
950 */
951 public void onHeaderClick(Header header, int position) {
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700952 if (header.fragment != null) {
953 if (mSinglePane) {
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700954 startWithFragment(header.fragment, header.fragmentArguments, null, 0);
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700955 } else {
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700956 switchToHeader(header);
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700957 }
958 } else if (header.intent != null) {
959 startActivity(header.intent);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700960 }
961 }
962
963 /**
964 * Start a new instance of this activity, showing only the given
965 * preference fragment. When launched in this mode, the header list
966 * will be hidden and the given preference fragment will be instantiated
967 * and fill the entire activity.
968 *
969 * @param fragmentName The name of the fragment to display.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700970 * @param args Optional arguments to supply to the fragment.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700971 */
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700972 public void startWithFragment(String fragmentName, Bundle args,
973 Fragment resultTo, int resultRequestCode) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700974 Intent intent = new Intent(Intent.ACTION_MAIN);
975 intent.setClass(this, getClass());
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700976 intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
977 intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
978 intent.putExtra(EXTRA_NO_HEADERS, true);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700979 if (resultTo == null) {
980 startActivity(intent);
981 } else {
982 resultTo.startActivityForResult(intent, resultRequestCode);
983 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700984 }
985
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700986 /**
987 * Change the base title of the bread crumbs for the current preferences.
988 * This will normally be called for you. See
989 * {@link android.app.FragmentBreadCrumbs} for more information.
990 */
991 public void showBreadCrumbs(CharSequence title, CharSequence shortTitle) {
992 if (mFragmentBreadCrumbs == null) {
Amith Yamasani3e860402010-12-10 14:20:51 -0800993 View crumbs = findViewById(android.R.id.title);
994 // For screens with a different kind of title, don't create breadcrumbs.
995 if (!(crumbs instanceof FragmentBreadCrumbs)) return;
Amith Yamasani3c9f5192010-12-08 16:48:31 -0800996 mFragmentBreadCrumbs = (FragmentBreadCrumbs) findViewById(android.R.id.title);
997 if (mFragmentBreadCrumbs == null) {
998 mFragmentBreadCrumbs = new FragmentBreadCrumbs(this);
999 ActionBar actionBar = getActionBar();
1000 if (actionBar != null) {
Adam Powell1264c332011-01-20 12:08:13 -08001001 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
1002 ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
1003 actionBar.setCustomView(mFragmentBreadCrumbs);
Amith Yamasani3c9f5192010-12-08 16:48:31 -08001004 }
Jim Millerc57406c2010-12-08 16:01:05 -08001005 }
Amith Yamasani3c9f5192010-12-08 16:48:31 -08001006 mFragmentBreadCrumbs.setMaxVisible(2);
1007 mFragmentBreadCrumbs.setActivity(this);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001008 }
1009 mFragmentBreadCrumbs.setTitle(title, shortTitle);
Amith Yamasanic9ecb732010-12-14 14:23:21 -08001010 mFragmentBreadCrumbs.setParentTitle(null, null, null);
1011 }
1012
1013 /**
1014 * Should be called after onCreate to ensure that the breadcrumbs, if any, were created.
1015 * This prepends a title to the fragment breadcrumbs and attaches a listener to any clicks
1016 * on the parent entry.
1017 * @param title the title for the breadcrumb
1018 * @param shortTitle the short title for the breadcrumb
1019 */
1020 public void setParentTitle(CharSequence title, CharSequence shortTitle,
1021 OnClickListener listener) {
1022 if (mFragmentBreadCrumbs != null) {
1023 mFragmentBreadCrumbs.setParentTitle(title, shortTitle, listener);
1024 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001025 }
1026
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001027 void setSelectedHeader(Header header) {
1028 mCurHeader = header;
1029 int index = mHeaders.indexOf(header);
1030 if (index >= 0) {
1031 getListView().setItemChecked(index, true);
1032 } else {
1033 getListView().clearChoices();
1034 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001035 if (header != null) {
Dianne Hackborn50ed8292010-12-03 12:30:21 -08001036 CharSequence title = header.getBreadCrumbTitle(getResources());
1037 if (title == null) title = header.getTitle(getResources());
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001038 if (title == null) title = getTitle();
Dianne Hackborn50ed8292010-12-03 12:30:21 -08001039 showBreadCrumbs(title, header.getBreadCrumbShortTitle(getResources()));
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001040 } else {
1041 showBreadCrumbs(getTitle(), null);
1042 }
1043 }
1044
Amith Yamasanif5cbaed2010-10-27 16:14:20 -07001045 private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001046 getFragmentManager().popBackStack(BACK_STACK_PREFS,
1047 FragmentManager.POP_BACK_STACK_INCLUSIVE);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001048 Fragment f = Fragment.instantiate(this, fragmentName, args);
Dianne Hackborn48e7b452011-01-17 12:28:35 -08001049 FragmentTransaction transaction = getFragmentManager().beginTransaction();
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001050 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
Chet Haase9ff82bf2010-10-05 14:30:51 -07001051 transaction.replace(com.android.internal.R.id.prefs, f);
Dianne Hackborncf407ad2011-03-11 13:17:57 -08001052 transaction.commitAllowingStateLoss();
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001053 }
1054
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001055 /**
1056 * When in two-pane mode, switch the fragment pane to show the given
1057 * preference fragment.
1058 *
1059 * @param fragmentName The name of the fragment to display.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001060 * @param args Optional arguments to supply to the fragment.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001061 */
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001062 public void switchToHeader(String fragmentName, Bundle args) {
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001063 setSelectedHeader(null);
Amith Yamasanif5cbaed2010-10-27 16:14:20 -07001064 switchToHeaderInner(fragmentName, args, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 }
1066
Andrew Stadleraa904f42010-09-02 14:50:08 -07001067 /**
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001068 * When in two-pane mode, switch to the fragment pane to show the given
1069 * preference fragment.
1070 *
1071 * @param header The new header to display.
1072 */
1073 public void switchToHeader(Header header) {
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001074 if (mCurHeader == header) {
1075 // This is the header we are currently displaying. Just make sure
1076 // to pop the stack up to its root state.
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001077 getFragmentManager().popBackStack(BACK_STACK_PREFS,
1078 FragmentManager.POP_BACK_STACK_INCLUSIVE);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001079 } else {
1080 int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
1081 switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
1082 setSelectedHeader(header);
1083 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001084 }
1085
1086 Header findBestMatchingHeader(Header cur, ArrayList<Header> from) {
1087 ArrayList<Header> matches = new ArrayList<Header>();
1088 for (int j=0; j<from.size(); j++) {
1089 Header oh = from.get(j);
1090 if (cur == oh || (cur.id != HEADER_ID_UNDEFINED && cur.id == oh.id)) {
1091 // Must be this one.
1092 matches.clear();
1093 matches.add(oh);
1094 break;
1095 }
1096 if (cur.fragment != null) {
1097 if (cur.fragment.equals(oh.fragment)) {
1098 matches.add(oh);
1099 }
1100 } else if (cur.intent != null) {
1101 if (cur.intent.equals(oh.intent)) {
1102 matches.add(oh);
1103 }
1104 } else if (cur.title != null) {
1105 if (cur.title.equals(oh.title)) {
1106 matches.add(oh);
1107 }
1108 }
1109 }
1110 final int NM = matches.size();
1111 if (NM == 1) {
1112 return matches.get(0);
1113 } else if (NM > 1) {
1114 for (int j=0; j<NM; j++) {
1115 Header oh = matches.get(j);
1116 if (cur.fragmentArguments != null &&
1117 cur.fragmentArguments.equals(oh.fragmentArguments)) {
1118 return oh;
1119 }
1120 if (cur.extras != null && cur.extras.equals(oh.extras)) {
1121 return oh;
1122 }
1123 if (cur.title != null && cur.title.equals(oh.title)) {
1124 return oh;
1125 }
1126 }
1127 }
1128 return null;
1129 }
1130
1131 /**
Andrew Stadleraa904f42010-09-02 14:50:08 -07001132 * Start a new fragment.
1133 *
1134 * @param fragment The fragment to start
1135 * @param push If true, the current fragment will be pushed onto the back stack. If false,
1136 * the current fragment will be replaced.
1137 */
1138 public void startPreferenceFragment(Fragment fragment, boolean push) {
Dianne Hackborn48e7b452011-01-17 12:28:35 -08001139 FragmentTransaction transaction = getFragmentManager().beginTransaction();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001140 transaction.replace(com.android.internal.R.id.prefs, fragment);
Andrew Stadleraa904f42010-09-02 14:50:08 -07001141 if (push) {
Chet Haase9ff82bf2010-10-05 14:30:51 -07001142 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
Andrew Stadleraa904f42010-09-02 14:50:08 -07001143 transaction.addToBackStack(BACK_STACK_PREFS);
Chet Haase9ff82bf2010-10-05 14:30:51 -07001144 } else {
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001145 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
Andrew Stadleraa904f42010-09-02 14:50:08 -07001146 }
Dianne Hackborncf407ad2011-03-11 13:17:57 -08001147 transaction.commitAllowingStateLoss();
Andrew Stadleraa904f42010-09-02 14:50:08 -07001148 }
1149
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001150 /**
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001151 * Start a new fragment containing a preference panel. If the prefences
1152 * are being displayed in multi-pane mode, the given fragment class will
1153 * be instantiated and placed in the appropriate pane. If running in
1154 * single-pane mode, a new activity will be launched in which to show the
1155 * fragment.
1156 *
1157 * @param fragmentClass Full name of the class implementing the fragment.
1158 * @param args Any desired arguments to supply to the fragment.
1159 * @param titleRes Optional resource identifier of the title of this
1160 * fragment.
1161 * @param titleText Optional text of the title of this fragment.
1162 * @param resultTo Optional fragment that result data should be sent to.
1163 * If non-null, resultTo.onActivityResult() will be called when this
1164 * preference panel is done. The launched panel must use
1165 * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
1166 * @param resultRequestCode If resultTo is non-null, this is the caller's
1167 * request code to be received with the resut.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001168 */
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001169 public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
1170 CharSequence titleText, Fragment resultTo, int resultRequestCode) {
1171 if (mSinglePane) {
1172 startWithFragment(fragmentClass, args, resultTo, resultRequestCode);
1173 } else {
1174 Fragment f = Fragment.instantiate(this, fragmentClass, args);
1175 if (resultTo != null) {
1176 f.setTargetFragment(resultTo, resultRequestCode);
1177 }
Dianne Hackborn48e7b452011-01-17 12:28:35 -08001178 FragmentTransaction transaction = getFragmentManager().beginTransaction();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001179 transaction.replace(com.android.internal.R.id.prefs, f);
1180 if (titleRes != 0) {
1181 transaction.setBreadCrumbTitle(titleRes);
1182 } else if (titleText != null) {
1183 transaction.setBreadCrumbTitle(titleText);
1184 }
1185 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
1186 transaction.addToBackStack(BACK_STACK_PREFS);
Dianne Hackborncf407ad2011-03-11 13:17:57 -08001187 transaction.commitAllowingStateLoss();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001188 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001189 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001190
1191 /**
1192 * Called by a preference panel fragment to finish itself.
1193 *
1194 * @param caller The fragment that is asking to be finished.
1195 * @param resultCode Optional result code to send back to the original
1196 * launching fragment.
1197 * @param resultData Optional result data to send back to the original
1198 * launching fragment.
1199 */
1200 public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
1201 if (mSinglePane) {
1202 setResult(resultCode, resultData);
1203 finish();
1204 } else {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001205 // XXX be smarter about popping the stack.
1206 onBackPressed();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001207 if (caller != null) {
1208 if (caller.getTargetFragment() != null) {
1209 caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
1210 resultCode, resultData);
1211 }
1212 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001213 }
1214 }
1215
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001216 @Override
1217 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001218 startPreferencePanel(pref.getFragment(), pref.getExtras(), 0, pref.getTitle(), null, 0);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001219 return true;
1220 }
1221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 /**
1223 * Posts a message to bind the preferences to the list view.
1224 * <p>
1225 * Binding late is preferred as any custom preference types created in
1226 * {@link #onCreate(Bundle)} are able to have their views recycled.
1227 */
1228 private void postBindPreferences() {
1229 if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
1230 mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
1231 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 private void bindPreferences() {
1234 final PreferenceScreen preferenceScreen = getPreferenceScreen();
1235 if (preferenceScreen != null) {
1236 preferenceScreen.bind(getListView());
Adam Powelle7fea452010-03-18 14:51:39 -07001237 if (mSavedInstanceState != null) {
1238 super.onRestoreInstanceState(mSavedInstanceState);
1239 mSavedInstanceState = null;
1240 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 }
1242 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245 * Returns the {@link PreferenceManager} used by this activity.
1246 * @return The {@link PreferenceManager}.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001247 *
1248 * @deprecated This function is not relevant for a modern fragment-based
1249 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001251 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 public PreferenceManager getPreferenceManager() {
1253 return mPreferenceManager;
1254 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 private void requirePreferenceManager() {
1257 if (mPreferenceManager == null) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001258 if (mAdapter == null) {
1259 throw new RuntimeException("This should be called after super.onCreate.");
1260 }
1261 throw new RuntimeException(
1262 "Modern two-pane PreferenceActivity requires use of a PreferenceFragment");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 }
1264 }
1265
1266 /**
1267 * Sets the root of the preference hierarchy that this activity is showing.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001268 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001270 *
1271 * @deprecated This function is not relevant for a modern fragment-based
1272 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001274 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001276 requirePreferenceManager();
1277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
1279 postBindPreferences();
1280 CharSequence title = getPreferenceScreen().getTitle();
1281 // Set the title of the activity
1282 if (title != null) {
1283 setTitle(title);
1284 }
1285 }
1286 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 /**
1289 * Gets the root of the preference hierarchy that this activity is showing.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001290 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 * @return The {@link PreferenceScreen} that is the root of the preference
1292 * hierarchy.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001293 *
1294 * @deprecated This function is not relevant for a modern fragment-based
1295 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001297 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 public PreferenceScreen getPreferenceScreen() {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001299 if (mPreferenceManager != null) {
1300 return mPreferenceManager.getPreferenceScreen();
1301 }
1302 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 /**
1306 * Adds preferences from activities that match the given {@link Intent}.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001307 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 * @param intent The {@link Intent} to query activities.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001309 *
1310 * @deprecated This function is not relevant for a modern fragment-based
1311 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001313 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 public void addPreferencesFromIntent(Intent intent) {
1315 requirePreferenceManager();
Freeman Ng19ea2e02010-03-25 15:09:00 -07001316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
1318 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 /**
1321 * Inflates the given XML resource and adds the preference hierarchy to the current
1322 * preference hierarchy.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001323 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 * @param preferencesResId The XML resource ID to inflate.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001325 *
1326 * @deprecated This function is not relevant for a modern fragment-based
1327 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001329 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 public void addPreferencesFromResource(int preferencesResId) {
1331 requirePreferenceManager();
Freeman Ng19ea2e02010-03-25 15:09:00 -07001332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 setPreferenceScreen(mPreferenceManager.inflateFromResource(this, preferencesResId,
1334 getPreferenceScreen()));
1335 }
1336
1337 /**
1338 * {@inheritDoc}
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001339 *
1340 * @deprecated This function is not relevant for a modern fragment-based
1341 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001343 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
1345 return false;
1346 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 /**
1349 * Finds a {@link Preference} based on its key.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001350 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 * @param key The key of the preference to retrieve.
1352 * @return The {@link Preference} with the key, or null.
1353 * @see PreferenceGroup#findPreference(CharSequence)
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001354 *
1355 * @deprecated This function is not relevant for a modern fragment-based
1356 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001358 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 public Preference findPreference(CharSequence key) {
Freeman Ng19ea2e02010-03-25 15:09:00 -07001360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 if (mPreferenceManager == null) {
1362 return null;
1363 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 return mPreferenceManager.findPreference(key);
1366 }
1367
1368 @Override
1369 protected void onNewIntent(Intent intent) {
1370 if (mPreferenceManager != null) {
1371 mPreferenceManager.dispatchNewIntent(intent);
1372 }
1373 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001374
1375 // give subclasses access to the Next button
1376 /** @hide */
1377 protected boolean hasNextButton() {
1378 return mNextButton != null;
1379 }
1380 /** @hide */
1381 protected Button getNextButton() {
1382 return mNextButton;
1383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384}