blob: 15d589895ac832d4d8ddf4866ebba9f1f6dca3be [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},
Dianne Hackborne72f2372011-03-16 10:43:18 -0700135 * this extra can also be specified to supply a Bundle of arguments to pass
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700136 * 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 /**
Dianne Hackborne72f2372011-03-16 10:43:18 -0700142 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
143 * this extra can also be specify to supply the title to be shown for
144 * that fragment.
145 */
146 public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":android:show_fragment_title";
147
148 /**
149 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
150 * this extra can also be specify to supply the short title to be shown for
151 * that fragment.
152 */
153 public static final String EXTRA_SHOW_FRAGMENT_SHORT_TITLE
154 = ":android:show_fragment_short_title";
155
156 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700157 * When starting this activity, the invoking Intent can contain this extra
158 * boolean that the header list should not be displayed. This is most often
159 * used in conjunction with {@link #EXTRA_SHOW_FRAGMENT} to launch
160 * the activity to display a specific fragment that the user has navigated
161 * to.
162 */
163 public static final String EXTRA_NO_HEADERS = ":android:no_headers";
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700164
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700165 private static final String BACK_STACK_PREFS = ":android:prefs";
166
Freeman Ng19ea2e02010-03-25 15:09:00 -0700167 // extras that allow any preference activity to be launched as part of a wizard
168
169 // show Back and Next buttons? takes boolean parameter
170 // Back will then return RESULT_CANCELED and Next RESULT_OK
171 private static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
172
Freeman Ng09dbf182010-08-11 15:45:01 -0700173 // add a Skip button?
174 private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip";
175
Freeman Ng19ea2e02010-03-25 15:09:00 -0700176 // specify custom text for the Back or Next buttons, or cause a button to not appear
177 // at all by setting it to null
178 private static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
179 private static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
180
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700181 // --- State for new mode when showing a list of headers + prefs fragment
182
183 private final ArrayList<Header> mHeaders = new ArrayList<Header>();
184
185 private HeaderAdapter mAdapter;
186
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700187 private FrameLayout mListFooter;
188
Amith Yamasani3c9f5192010-12-08 16:48:31 -0800189 private ViewGroup mPrefsContainer;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700190
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700191 private FragmentBreadCrumbs mFragmentBreadCrumbs;
192
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700193 private boolean mSinglePane;
194
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700195 private Header mCurHeader;
196
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700197 // --- State for old mode when showing a single preference list
Freeman Ng19ea2e02010-03-25 15:09:00 -0700198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 private PreferenceManager mPreferenceManager;
Freeman Ng19ea2e02010-03-25 15:09:00 -0700200
Adam Powelle7fea452010-03-18 14:51:39 -0700201 private Bundle mSavedInstanceState;
202
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700203 // --- Common state
204
205 private Button mNextButton;
206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 /**
208 * The starting request code given out to preference framework.
209 */
210 private static final int FIRST_REQUEST_CODE = 100;
Freeman Ng19ea2e02010-03-25 15:09:00 -0700211
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700212 private static final int MSG_BIND_PREFERENCES = 1;
213 private static final int MSG_BUILD_HEADERS = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 private Handler mHandler = new Handler() {
215 @Override
216 public void handleMessage(Message msg) {
217 switch (msg.what) {
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700218 case MSG_BIND_PREFERENCES: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 bindPreferences();
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700220 } break;
221 case MSG_BUILD_HEADERS: {
222 ArrayList<Header> oldHeaders = new ArrayList<Header>(mHeaders);
223 mHeaders.clear();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700224 onBuildHeaders(mHeaders);
Andrew Stadler83681eb2010-11-04 15:49:05 -0700225 if (mAdapter != null) {
226 mAdapter.notifyDataSetChanged();
227 }
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700228 Header header = onGetNewHeader();
229 if (header != null && header.fragment != null) {
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700230 Header mappedHeader = findBestMatchingHeader(header, oldHeaders);
231 if (mappedHeader == null || mCurHeader != mappedHeader) {
232 switchToHeader(header);
233 }
234 } else if (mCurHeader != null) {
235 Header mappedHeader = findBestMatchingHeader(mCurHeader, mHeaders);
236 if (mappedHeader != null) {
237 setSelectedHeader(mappedHeader);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700238 }
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700239 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700240 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 }
242 }
243 };
244
Andrew Stadler468c3232010-08-17 16:16:42 -0700245 private static class HeaderAdapter extends ArrayAdapter<Header> {
246 private static class HeaderViewHolder {
247 ImageView icon;
248 TextView title;
249 TextView summary;
250 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700251
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700252 private LayoutInflater mInflater;
253
254 public HeaderAdapter(Context context, List<Header> objects) {
255 super(context, 0, objects);
256 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
257 }
258
259 @Override
260 public View getView(int position, View convertView, ViewGroup parent) {
261 HeaderViewHolder holder;
262 View view;
263
264 if (convertView == null) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -0700265 view = mInflater.inflate(com.android.internal.R.layout.preference_header_item,
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700266 parent, false);
267 holder = new HeaderViewHolder();
Andrew Stadler468c3232010-08-17 16:16:42 -0700268 holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
269 holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
270 holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700271 view.setTag(holder);
272 } else {
273 view = convertView;
Andrew Stadler468c3232010-08-17 16:16:42 -0700274 holder = (HeaderViewHolder) view.getTag();
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700275 }
276
Andrew Stadler468c3232010-08-17 16:16:42 -0700277 // All view fields must be updated every time, because the view may be recycled
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700278 Header header = getItem(position);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700279 holder.icon.setImageResource(header.iconRes);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800280 holder.title.setText(header.getTitle(getContext().getResources()));
281 CharSequence summary = header.getSummary(getContext().getResources());
282 if (!TextUtils.isEmpty(summary)) {
Andrew Stadler468c3232010-08-17 16:16:42 -0700283 holder.summary.setVisibility(View.VISIBLE);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800284 holder.summary.setText(summary);
285 } else {
286 holder.summary.setVisibility(View.GONE);
Andrew Stadler468c3232010-08-17 16:16:42 -0700287 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700288
289 return view;
290 }
291 }
292
293 /**
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700294 * Default value for {@link Header#id Header.id} indicating that no
295 * identifier value is set. All other values (including those below -1)
296 * are valid.
297 */
298 public static final long HEADER_ID_UNDEFINED = -1;
299
300 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700301 * Description of a single Header item that the user can select.
302 */
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700303 public static final class Header implements Parcelable {
304 /**
305 * Identifier for this header, to correlate with a new list when
306 * it is updated. The default value is
307 * {@link PreferenceActivity#HEADER_ID_UNDEFINED}, meaning no id.
308 * @attr ref android.R.styleable#PreferenceHeader_id
309 */
310 public long id = HEADER_ID_UNDEFINED;
311
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700312 /**
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800313 * Resource ID of title of the header that is shown to the user.
314 * @attr ref android.R.styleable#PreferenceHeader_title
315 */
316 public int titleRes;
317
318 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700319 * Title of the header that is shown to the user.
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700320 * @attr ref android.R.styleable#PreferenceHeader_title
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700321 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700322 public CharSequence title;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700323
324 /**
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800325 * Resource ID of optional summary describing what this header controls.
326 * @attr ref android.R.styleable#PreferenceHeader_summary
327 */
328 public int summaryRes;
329
330 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700331 * Optional summary describing what this header controls.
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700332 * @attr ref android.R.styleable#PreferenceHeader_summary
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700333 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700334 public CharSequence summary;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700335
336 /**
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800337 * Resource ID of optional text to show as the title in the bread crumb.
338 * @attr ref android.R.styleable#PreferenceHeader_breadCrumbTitle
339 */
340 public int breadCrumbTitleRes;
341
342 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700343 * Optional text to show as the title in the bread crumb.
344 * @attr ref android.R.styleable#PreferenceHeader_breadCrumbTitle
345 */
346 public CharSequence breadCrumbTitle;
347
348 /**
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800349 * Resource ID of optional text to show as the short title in the bread crumb.
350 * @attr ref android.R.styleable#PreferenceHeader_breadCrumbShortTitle
351 */
352 public int breadCrumbShortTitleRes;
353
354 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700355 * Optional text to show as the short title in the bread crumb.
356 * @attr ref android.R.styleable#PreferenceHeader_breadCrumbShortTitle
357 */
358 public CharSequence breadCrumbShortTitle;
359
360 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700361 * Optional icon resource to show for this header.
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700362 * @attr ref android.R.styleable#PreferenceHeader_icon
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700363 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700364 public int iconRes;
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700365
366 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700367 * Full class name of the fragment to display when this header is
368 * selected.
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -0700369 * @attr ref android.R.styleable#PreferenceHeader_fragment
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700370 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700371 public String fragment;
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700372
373 /**
374 * Optional arguments to supply to the fragment when it is
375 * instantiated.
376 */
Andrew Stadler468c3232010-08-17 16:16:42 -0700377 public Bundle fragmentArguments;
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700378
379 /**
380 * Intent to launch when the preference is selected.
381 */
382 public Intent intent;
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700383
384 /**
385 * Optional additional data for use by subclasses of PreferenceActivity.
386 */
387 public Bundle extras;
388
389 public Header() {
390 }
391
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800392 /**
393 * Return the currently set title. If {@link #titleRes} is set,
394 * this resource is loaded from <var>res</var> and returned. Otherwise
395 * {@link #title} is returned.
396 */
397 public CharSequence getTitle(Resources res) {
398 if (titleRes != 0) {
399 return res.getText(titleRes);
400 }
401 return title;
402 }
403
404 /**
405 * Return the currently set summary. If {@link #summaryRes} is set,
406 * this resource is loaded from <var>res</var> and returned. Otherwise
407 * {@link #summary} is returned.
408 */
409 public CharSequence getSummary(Resources res) {
410 if (summaryRes != 0) {
411 return res.getText(summaryRes);
412 }
Dianne Hackborn9d071802010-12-08 14:49:15 -0800413 return summary;
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800414 }
415
416 /**
417 * Return the currently set bread crumb title. If {@link #breadCrumbTitleRes} is set,
418 * this resource is loaded from <var>res</var> and returned. Otherwise
419 * {@link #breadCrumbTitle} is returned.
420 */
421 public CharSequence getBreadCrumbTitle(Resources res) {
422 if (breadCrumbTitleRes != 0) {
423 return res.getText(breadCrumbTitleRes);
424 }
425 return breadCrumbTitle;
426 }
427
428 /**
429 * Return the currently set bread crumb short title. If
430 * {@link #breadCrumbShortTitleRes} is set,
431 * this resource is loaded from <var>res</var> and returned. Otherwise
432 * {@link #breadCrumbShortTitle} is returned.
433 */
434 public CharSequence getBreadCrumbShortTitle(Resources res) {
435 if (breadCrumbShortTitleRes != 0) {
436 return res.getText(breadCrumbShortTitleRes);
437 }
438 return breadCrumbShortTitle;
439 }
440
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700441 @Override
442 public int describeContents() {
443 return 0;
444 }
445
446 @Override
447 public void writeToParcel(Parcel dest, int flags) {
448 dest.writeLong(id);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800449 dest.writeInt(titleRes);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700450 TextUtils.writeToParcel(title, dest, flags);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800451 dest.writeInt(summaryRes);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700452 TextUtils.writeToParcel(summary, dest, flags);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800453 dest.writeInt(breadCrumbTitleRes);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700454 TextUtils.writeToParcel(breadCrumbTitle, dest, flags);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800455 dest.writeInt(breadCrumbShortTitleRes);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700456 TextUtils.writeToParcel(breadCrumbShortTitle, dest, flags);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700457 dest.writeInt(iconRes);
458 dest.writeString(fragment);
459 dest.writeBundle(fragmentArguments);
460 if (intent != null) {
461 dest.writeInt(1);
462 intent.writeToParcel(dest, flags);
463 } else {
464 dest.writeInt(0);
465 }
466 dest.writeBundle(extras);
467 }
468
469 public void readFromParcel(Parcel in) {
470 id = in.readLong();
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800471 titleRes = in.readInt();
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700472 title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800473 summaryRes = in.readInt();
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700474 summary = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800475 breadCrumbTitleRes = in.readInt();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700476 breadCrumbTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800477 breadCrumbShortTitleRes = in.readInt();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700478 breadCrumbShortTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700479 iconRes = in.readInt();
480 fragment = in.readString();
481 fragmentArguments = in.readBundle();
482 if (in.readInt() != 0) {
483 intent = Intent.CREATOR.createFromParcel(in);
484 }
485 extras = in.readBundle();
486 }
487
488 Header(Parcel in) {
489 readFromParcel(in);
490 }
491
492 public static final Creator<Header> CREATOR = new Creator<Header>() {
493 public Header createFromParcel(Parcel source) {
494 return new Header(source);
495 }
496 public Header[] newArray(int size) {
497 return new Header[size];
498 }
499 };
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700500 }
501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 @Override
503 protected void onCreate(Bundle savedInstanceState) {
504 super.onCreate(savedInstanceState);
505
Dianne Hackborne72f2372011-03-16 10:43:18 -0700506 if (getResources().getConfiguration().isLayoutSizeAtLeast(
507 Configuration.SCREENLAYOUT_SIZE_LARGE)) {
508 setContentView(com.android.internal.R.layout.preference_list_content_large);
509 } else {
510 setContentView(com.android.internal.R.layout.preference_list_content);
511 }
Freeman Ng19ea2e02010-03-25 15:09:00 -0700512
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700513 mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer);
Amith Yamasani3c9f5192010-12-08 16:48:31 -0800514 mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs_frame);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700515 boolean hidingHeaders = onIsHidingHeaders();
516 mSinglePane = hidingHeaders || !onIsMultiPane();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700517 String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
518 Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
Dianne Hackborne72f2372011-03-16 10:43:18 -0700519 int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0);
520 int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700521
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700522 if (savedInstanceState != null) {
523 // We are restarting from a previous saved state; used that to
524 // initialize, instead of starting fresh.
525 ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG);
526 if (headers != null) {
527 mHeaders.addAll(headers);
528 int curHeader = savedInstanceState.getInt(CUR_HEADER_TAG,
529 (int)HEADER_ID_UNDEFINED);
530 if (curHeader >= 0 && curHeader < mHeaders.size()) {
531 setSelectedHeader(mHeaders.get(curHeader));
532 }
533 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700534
535 } else {
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700536 if (initialFragment != null && mSinglePane) {
537 // If we are just showing a fragment, we want to run in
538 // new fragment mode, but don't need to compute and show
539 // the headers.
540 switchToHeader(initialFragment, initialArguments);
Dianne Hackborne72f2372011-03-16 10:43:18 -0700541 if (initialTitle != 0) {
542 CharSequence initialTitleStr = getText(initialTitle);
543 CharSequence initialShortTitleStr = initialShortTitle != 0
544 ? getText(initialShortTitle) : null;
545 showBreadCrumbs(initialTitleStr, initialShortTitleStr);
546 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700547
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700548 } else {
549 // We need to try to build the headers.
550 onBuildHeaders(mHeaders);
551
552 // If there are headers, then at this point we need to show
553 // them and, depending on the screen, we may also show in-line
554 // the currently selected preference fragment.
555 if (mHeaders.size() > 0) {
556 if (!mSinglePane) {
557 if (initialFragment == null) {
558 Header h = onGetInitialHeader();
559 switchToHeader(h);
560 } else {
561 switchToHeader(initialFragment, initialArguments);
562 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700563 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700564 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700565 }
566 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700567
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700568 // The default configuration is to only show the list view. Adjust
569 // visibility for other configurations.
570 if (initialFragment != null && mSinglePane) {
571 // Single pane, showing just a prefs fragment.
Amith Yamasani05fbc312010-09-26 13:29:01 -0700572 findViewById(com.android.internal.R.id.headers).setVisibility(View.GONE);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700573 mPrefsContainer.setVisibility(View.VISIBLE);
574 } else if (mHeaders.size() > 0) {
575 mAdapter = new HeaderAdapter(this, mHeaders);
576 setListAdapter(mAdapter);
577 if (!mSinglePane) {
578 // Multi-pane.
579 getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
Dianne Hackbornd0fa3712010-09-14 18:57:14 -0700580 if (mCurHeader != null) {
581 setSelectedHeader(mCurHeader);
582 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700583 mPrefsContainer.setVisibility(View.VISIBLE);
584 }
585 } else {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700586 // If there are no headers, we are in the old "just show a screen
587 // of preferences" mode.
Dianne Hackborne72f2372011-03-16 10:43:18 -0700588 if (getResources().getConfiguration().isLayoutSizeAtLeast(
589 Configuration.SCREENLAYOUT_SIZE_LARGE)) {
590 setContentView(com.android.internal.R.layout.preference_list_content_single_large);
591 } else {
592 setContentView(com.android.internal.R.layout.preference_list_content_single);
593 }
Amith Yamasani8da35292010-11-05 09:15:51 -0700594 mListFooter = (FrameLayout) findViewById(com.android.internal.R.id.list_footer);
Amith Yamasani3c9f5192010-12-08 16:48:31 -0800595 mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs);
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700596 mPreferenceManager = new PreferenceManager(this, FIRST_REQUEST_CODE);
597 mPreferenceManager.setOnPreferenceTreeClickListener(this);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700598 }
599
600 getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
601
Freeman Ng19ea2e02010-03-25 15:09:00 -0700602 // see if we should show Back/Next buttons
603 Intent intent = getIntent();
604 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
605
606 findViewById(com.android.internal.R.id.button_bar).setVisibility(View.VISIBLE);
607
608 Button backButton = (Button)findViewById(com.android.internal.R.id.back_button);
609 backButton.setOnClickListener(new OnClickListener() {
610 public void onClick(View v) {
611 setResult(RESULT_CANCELED);
612 finish();
613 }
614 });
Freeman Ng09dbf182010-08-11 15:45:01 -0700615 Button skipButton = (Button)findViewById(com.android.internal.R.id.skip_button);
616 skipButton.setOnClickListener(new OnClickListener() {
617 public void onClick(View v) {
618 setResult(RESULT_OK);
619 finish();
620 }
621 });
Freeman Ng19ea2e02010-03-25 15:09:00 -0700622 mNextButton = (Button)findViewById(com.android.internal.R.id.next_button);
623 mNextButton.setOnClickListener(new OnClickListener() {
624 public void onClick(View v) {
625 setResult(RESULT_OK);
626 finish();
627 }
628 });
629
630 // set our various button parameters
631 if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
632 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
633 if (TextUtils.isEmpty(buttonText)) {
634 mNextButton.setVisibility(View.GONE);
635 }
636 else {
637 mNextButton.setText(buttonText);
638 }
639 }
640 if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
641 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
642 if (TextUtils.isEmpty(buttonText)) {
643 backButton.setVisibility(View.GONE);
644 }
645 else {
646 backButton.setText(buttonText);
647 }
648 }
Freeman Ng09dbf182010-08-11 15:45:01 -0700649 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
650 skipButton.setVisibility(View.VISIBLE);
651 }
Freeman Ng19ea2e02010-03-25 15:09:00 -0700652 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700653 }
Freeman Ng19ea2e02010-03-25 15:09:00 -0700654
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700655 /**
Dianne Hackborn291905e2010-08-17 15:17:15 -0700656 * Returns true if this activity is currently showing the header list.
657 */
658 public boolean hasHeaders() {
659 return getListView().getVisibility() == View.VISIBLE
660 && mPreferenceManager == null;
661 }
662
663 /**
664 * Returns true if this activity is showing multiple panes -- the headers
665 * and a preference fragment.
666 */
667 public boolean isMultiPane() {
668 return hasHeaders() && mPrefsContainer.getVisibility() == View.VISIBLE;
669 }
670
671 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700672 * Called to determine if the activity should run in multi-pane mode.
673 * The default implementation returns true if the screen is large
674 * enough.
675 */
676 public boolean onIsMultiPane() {
677 Configuration config = getResources().getConfiguration();
678 if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700679 == Configuration.SCREENLAYOUT_SIZE_XLARGE) {
680 return true;
681 }
682 if ((config.screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK)
683 == Configuration.SCREENLAYOUT_SIZE_LARGE
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700684 && config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
685 return true;
686 }
687 return false;
688 }
689
690 /**
Dianne Hackborn291905e2010-08-17 15:17:15 -0700691 * Called to determine whether the header list should be hidden.
692 * The default implementation returns the
693 * value given in {@link #EXTRA_NO_HEADERS} or false if it is not supplied.
694 * This is set to false, for example, when the activity is being re-launched
695 * to show a particular preference activity.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700696 */
697 public boolean onIsHidingHeaders() {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700698 return getIntent().getBooleanExtra(EXTRA_NO_HEADERS, false);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700699 }
700
701 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700702 * Called to determine the initial header to be shown. The default
703 * implementation simply returns the fragment of the first header. Note
704 * that the returned Header object does not actually need to exist in
705 * your header list -- whatever its fragment is will simply be used to
706 * show for the initial UI.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700707 */
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700708 public Header onGetInitialHeader() {
709 return mHeaders.get(0);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700710 }
711
712 /**
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700713 * Called after the header list has been updated ({@link #onBuildHeaders}
714 * has been called and returned due to {@link #invalidateHeaders()}) to
715 * specify the header that should now be selected. The default implementation
716 * returns null to keep whatever header is currently selected.
717 */
718 public Header onGetNewHeader() {
719 return null;
720 }
721
722 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700723 * Called when the activity needs its list of headers build. By
724 * implementing this and adding at least one item to the list, you
725 * will cause the activity to run in its modern fragment mode. Note
726 * that this function may not always be called; for example, if the
727 * activity has been asked to display a particular fragment without
728 * the header list, there is no need to build the headers.
729 *
730 * <p>Typical implementations will use {@link #loadHeadersFromResource}
731 * to fill in the list from a resource.
732 *
733 * @param target The list in which to place the headers.
734 */
735 public void onBuildHeaders(List<Header> target) {
736 }
737
738 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700739 * Call when you need to change the headers being displayed. Will result
740 * in onBuildHeaders() later being called to retrieve the new list.
741 */
742 public void invalidateHeaders() {
743 if (!mHandler.hasMessages(MSG_BUILD_HEADERS)) {
744 mHandler.sendEmptyMessage(MSG_BUILD_HEADERS);
745 }
746 }
747
748 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700749 * Parse the given XML file as a header description, adding each
750 * parsed Header into the target list.
751 *
752 * @param resid The XML resource to load and parse.
753 * @param target The list in which the parsed headers should be placed.
754 */
755 public void loadHeadersFromResource(int resid, List<Header> target) {
756 XmlResourceParser parser = null;
757 try {
758 parser = getResources().getXml(resid);
759 AttributeSet attrs = Xml.asAttributeSet(parser);
760
761 int type;
762 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
763 && type != XmlPullParser.START_TAG) {
764 }
765
766 String nodeName = parser.getName();
Dianne Hackborndef15372010-08-15 12:43:52 -0700767 if (!"preference-headers".equals(nodeName)) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700768 throw new RuntimeException(
Dianne Hackborndef15372010-08-15 12:43:52 -0700769 "XML document must start with <preference-headers> tag; found"
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700770 + nodeName + " at " + parser.getPositionDescription());
771 }
772
Dianne Hackborndef15372010-08-15 12:43:52 -0700773 Bundle curBundle = null;
774
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700775 final int outerDepth = parser.getDepth();
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700776 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
777 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
778 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
779 continue;
780 }
781
782 nodeName = parser.getName();
Dianne Hackborndef15372010-08-15 12:43:52 -0700783 if ("header".equals(nodeName)) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700784 Header header = new Header();
785
786 TypedArray sa = getResources().obtainAttributes(attrs,
787 com.android.internal.R.styleable.PreferenceHeader);
Amith Yamasanied13cde2010-09-17 16:56:47 -0700788 header.id = sa.getResourceId(
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700789 com.android.internal.R.styleable.PreferenceHeader_id,
790 (int)HEADER_ID_UNDEFINED);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800791 TypedValue tv = sa.peekValue(
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700792 com.android.internal.R.styleable.PreferenceHeader_title);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800793 if (tv != null && tv.type == TypedValue.TYPE_STRING) {
794 if (tv.resourceId != 0) {
795 header.titleRes = tv.resourceId;
796 } else {
797 header.title = tv.string;
798 }
799 }
800 tv = sa.peekValue(
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700801 com.android.internal.R.styleable.PreferenceHeader_summary);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800802 if (tv != null && tv.type == TypedValue.TYPE_STRING) {
803 if (tv.resourceId != 0) {
804 header.summaryRes = tv.resourceId;
805 } else {
806 header.summary = tv.string;
807 }
808 }
809 tv = sa.peekValue(
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700810 com.android.internal.R.styleable.PreferenceHeader_breadCrumbTitle);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800811 if (tv != null && tv.type == TypedValue.TYPE_STRING) {
812 if (tv.resourceId != 0) {
813 header.breadCrumbTitleRes = tv.resourceId;
814 } else {
815 header.breadCrumbTitle = tv.string;
816 }
817 }
818 tv = sa.peekValue(
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700819 com.android.internal.R.styleable.PreferenceHeader_breadCrumbShortTitle);
Dianne Hackborn50ed8292010-12-03 12:30:21 -0800820 if (tv != null && tv.type == TypedValue.TYPE_STRING) {
821 if (tv.resourceId != 0) {
822 header.breadCrumbShortTitleRes = tv.resourceId;
823 } else {
824 header.breadCrumbShortTitle = tv.string;
825 }
826 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700827 header.iconRes = sa.getResourceId(
828 com.android.internal.R.styleable.PreferenceHeader_icon, 0);
829 header.fragment = sa.getString(
830 com.android.internal.R.styleable.PreferenceHeader_fragment);
831 sa.recycle();
832
Dianne Hackborndef15372010-08-15 12:43:52 -0700833 if (curBundle == null) {
834 curBundle = new Bundle();
835 }
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700836
837 final int innerDepth = parser.getDepth();
838 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
839 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
840 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
841 continue;
842 }
843
844 String innerNodeName = parser.getName();
845 if (innerNodeName.equals("extra")) {
846 getResources().parseBundleExtra("extra", attrs, curBundle);
847 XmlUtils.skipCurrentTag(parser);
848
849 } else if (innerNodeName.equals("intent")) {
850 header.intent = Intent.parseIntent(getResources(), parser, attrs);
851
852 } else {
853 XmlUtils.skipCurrentTag(parser);
854 }
855 }
856
Dianne Hackborndef15372010-08-15 12:43:52 -0700857 if (curBundle.size() > 0) {
858 header.fragmentArguments = curBundle;
859 curBundle = null;
860 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700861
Dianne Hackborndef15372010-08-15 12:43:52 -0700862 target.add(header);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700863 } else {
864 XmlUtils.skipCurrentTag(parser);
865 }
866 }
867
868 } catch (XmlPullParserException e) {
869 throw new RuntimeException("Error parsing headers", e);
870 } catch (IOException e) {
871 throw new RuntimeException("Error parsing headers", e);
872 } finally {
873 if (parser != null) parser.close();
874 }
875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 }
877
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700878 /**
879 * Set a footer that should be shown at the bottom of the header list.
880 */
881 public void setListFooter(View view) {
882 mListFooter.removeAllViews();
883 mListFooter.addView(view, new FrameLayout.LayoutParams(
884 FrameLayout.LayoutParams.MATCH_PARENT,
885 FrameLayout.LayoutParams.WRAP_CONTENT));
886 }
887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 @Override
889 protected void onStop() {
890 super.onStop();
Freeman Ng19ea2e02010-03-25 15:09:00 -0700891
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700892 if (mPreferenceManager != null) {
893 mPreferenceManager.dispatchActivityStop();
894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 }
896
897 @Override
898 protected void onDestroy() {
899 super.onDestroy();
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700900
901 if (mPreferenceManager != null) {
902 mPreferenceManager.dispatchActivityDestroy();
903 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 }
905
906 @Override
907 protected void onSaveInstanceState(Bundle outState) {
908 super.onSaveInstanceState(outState);
909
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700910 if (mHeaders.size() > 0) {
911 outState.putParcelableArrayList(HEADERS_TAG, mHeaders);
912 if (mCurHeader != null) {
913 int index = mHeaders.indexOf(mCurHeader);
914 if (index >= 0) {
915 outState.putInt(CUR_HEADER_TAG, index);
916 }
917 }
918 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700919
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700920 if (mPreferenceManager != null) {
921 final PreferenceScreen preferenceScreen = getPreferenceScreen();
922 if (preferenceScreen != null) {
923 Bundle container = new Bundle();
924 preferenceScreen.saveHierarchyState(container);
925 outState.putBundle(PREFERENCES_TAG, container);
926 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 }
928 }
929
930 @Override
931 protected void onRestoreInstanceState(Bundle state) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700932 if (mPreferenceManager != null) {
933 Bundle container = state.getBundle(PREFERENCES_TAG);
934 if (container != null) {
935 final PreferenceScreen preferenceScreen = getPreferenceScreen();
936 if (preferenceScreen != null) {
937 preferenceScreen.restoreHierarchyState(container);
938 mSavedInstanceState = state;
939 return;
940 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 }
942 }
Adam Powelle7fea452010-03-18 14:51:39 -0700943
944 // Only call this if we didn't save the instance state for later.
945 // If we did save it, it will be restored when we bind the adapter.
946 super.onRestoreInstanceState(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 }
948
949 @Override
950 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
951 super.onActivityResult(requestCode, resultCode, data);
Freeman Ng19ea2e02010-03-25 15:09:00 -0700952
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700953 if (mPreferenceManager != null) {
954 mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 }
957
958 @Override
959 public void onContentChanged() {
960 super.onContentChanged();
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700961
962 if (mPreferenceManager != null) {
963 postBindPreferences();
964 }
965 }
966
967 @Override
968 protected void onListItemClick(ListView l, View v, int position, long id) {
969 super.onListItemClick(l, v, position, id);
970
971 if (mAdapter != null) {
972 onHeaderClick(mHeaders.get(position), position);
973 }
974 }
975
976 /**
977 * Called when the user selects an item in the header list. The default
Dianne Hackborne72f2372011-03-16 10:43:18 -0700978 * implementation will call either
979 * {@link #startWithFragment(String, Bundle, Fragment, int, int, int)}
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700980 * or {@link #switchToHeader(Header)} as appropriate.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -0700981 *
982 * @param header The header that was selected.
983 * @param position The header's position in the list.
984 */
985 public void onHeaderClick(Header header, int position) {
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700986 if (header.fragment != null) {
987 if (mSinglePane) {
Dianne Hackborne72f2372011-03-16 10:43:18 -0700988 int titleRes = header.breadCrumbTitleRes;
989 int shortTitleRes = header.breadCrumbShortTitleRes;
990 if (titleRes == 0) {
991 titleRes = header.titleRes;
992 shortTitleRes = 0;
993 }
994 startWithFragment(header.fragment, header.fragmentArguments, null, 0,
995 titleRes, shortTitleRes);
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700996 } else {
Dianne Hackborna21e3da2010-09-12 19:27:46 -0700997 switchToHeader(header);
Dianne Hackborn5c769a42010-08-26 17:08:08 -0700998 }
999 } else if (header.intent != null) {
1000 startActivity(header.intent);
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001001 }
1002 }
1003
1004 /**
Dianne Hackborne72f2372011-03-16 10:43:18 -07001005 * Called by {@link #startWithFragment(String, Bundle, Fragment, int, int, int)} when
Dianne Hackbornb1a6e4392011-03-15 16:23:01 -07001006 * in single-pane mode, to build an Intent to launch a new activity showing
1007 * the selected fragment. The default implementation constructs an Intent
1008 * that re-launches the current activity with the appropriate arguments to
1009 * display the fragment.
1010 *
1011 * @param fragmentName The name of the fragment to display.
1012 * @param args Optional arguments to supply to the fragment.
Dianne Hackborne72f2372011-03-16 10:43:18 -07001013 * @param titleRes Optional resource ID of title to show for this item.
1014 * @param titleRes Optional resource ID of short title to show for this item.
Dianne Hackbornb1a6e4392011-03-15 16:23:01 -07001015 * @return Returns an Intent that can be launched to display the given
1016 * fragment.
1017 */
Dianne Hackborne72f2372011-03-16 10:43:18 -07001018 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
1019 int titleRes, int shortTitleRes) {
Dianne Hackbornb1a6e4392011-03-15 16:23:01 -07001020 Intent intent = new Intent(Intent.ACTION_MAIN);
1021 intent.setClass(this, getClass());
1022 intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
1023 intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
Dianne Hackborne72f2372011-03-16 10:43:18 -07001024 intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, titleRes);
1025 intent.putExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, shortTitleRes);
Dianne Hackbornb1a6e4392011-03-15 16:23:01 -07001026 intent.putExtra(EXTRA_NO_HEADERS, true);
1027 return intent;
1028 }
1029
1030 /**
Dianne Hackborne72f2372011-03-16 10:43:18 -07001031 * Like {@link #startWithFragment(String, Bundle, Fragment, int, int, int)}
1032 * but uses a 0 titleRes.
1033 */
1034 public void startWithFragment(String fragmentName, Bundle args,
1035 Fragment resultTo, int resultRequestCode) {
1036 startWithFragment(fragmentName, args, resultTo, resultRequestCode, 0, 0);
1037 }
1038
1039 /**
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001040 * Start a new instance of this activity, showing only the given
1041 * preference fragment. When launched in this mode, the header list
1042 * will be hidden and the given preference fragment will be instantiated
1043 * and fill the entire activity.
1044 *
1045 * @param fragmentName The name of the fragment to display.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001046 * @param args Optional arguments to supply to the fragment.
Dianne Hackbornb1a6e4392011-03-15 16:23:01 -07001047 * @param resultTo Option fragment that should receive the result of
1048 * the activity launch.
1049 * @param resultRequestCode If resultTo is non-null, this is the request
1050 * code in which to report the result.
Dianne Hackborne72f2372011-03-16 10:43:18 -07001051 * @param titleRes Resource ID of string to display for the title of
1052 * this set of preferences.
1053 * @param titleRes Resource ID of string to display for the short title of
1054 * this set of preferences.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001055 */
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001056 public void startWithFragment(String fragmentName, Bundle args,
Dianne Hackborne72f2372011-03-16 10:43:18 -07001057 Fragment resultTo, int resultRequestCode, int titleRes, int shortTitleRes) {
1058 Intent intent = onBuildStartFragmentIntent(fragmentName, args, titleRes, shortTitleRes);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001059 if (resultTo == null) {
1060 startActivity(intent);
1061 } else {
1062 resultTo.startActivityForResult(intent, resultRequestCode);
1063 }
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001064 }
1065
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001066 /**
1067 * Change the base title of the bread crumbs for the current preferences.
1068 * This will normally be called for you. See
1069 * {@link android.app.FragmentBreadCrumbs} for more information.
1070 */
1071 public void showBreadCrumbs(CharSequence title, CharSequence shortTitle) {
1072 if (mFragmentBreadCrumbs == null) {
Amith Yamasani3e860402010-12-10 14:20:51 -08001073 View crumbs = findViewById(android.R.id.title);
1074 // For screens with a different kind of title, don't create breadcrumbs.
Dianne Hackborne72f2372011-03-16 10:43:18 -07001075 try {
1076 mFragmentBreadCrumbs = (FragmentBreadCrumbs)crumbs;
1077 } catch (ClassCastException e) {
1078 return;
1079 }
Amith Yamasani3c9f5192010-12-08 16:48:31 -08001080 if (mFragmentBreadCrumbs == null) {
Dianne Hackborne72f2372011-03-16 10:43:18 -07001081 if (title != null) {
1082 setTitle(title);
Amith Yamasani3c9f5192010-12-08 16:48:31 -08001083 }
Dianne Hackborne72f2372011-03-16 10:43:18 -07001084 return;
Jim Millerc57406c2010-12-08 16:01:05 -08001085 }
Amith Yamasani3c9f5192010-12-08 16:48:31 -08001086 mFragmentBreadCrumbs.setMaxVisible(2);
1087 mFragmentBreadCrumbs.setActivity(this);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001088 }
1089 mFragmentBreadCrumbs.setTitle(title, shortTitle);
Amith Yamasanic9ecb732010-12-14 14:23:21 -08001090 mFragmentBreadCrumbs.setParentTitle(null, null, null);
1091 }
1092
1093 /**
1094 * Should be called after onCreate to ensure that the breadcrumbs, if any, were created.
1095 * This prepends a title to the fragment breadcrumbs and attaches a listener to any clicks
1096 * on the parent entry.
1097 * @param title the title for the breadcrumb
1098 * @param shortTitle the short title for the breadcrumb
1099 */
1100 public void setParentTitle(CharSequence title, CharSequence shortTitle,
1101 OnClickListener listener) {
1102 if (mFragmentBreadCrumbs != null) {
1103 mFragmentBreadCrumbs.setParentTitle(title, shortTitle, listener);
1104 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001105 }
1106
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001107 void setSelectedHeader(Header header) {
1108 mCurHeader = header;
1109 int index = mHeaders.indexOf(header);
1110 if (index >= 0) {
1111 getListView().setItemChecked(index, true);
1112 } else {
1113 getListView().clearChoices();
1114 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001115 if (header != null) {
Dianne Hackborn50ed8292010-12-03 12:30:21 -08001116 CharSequence title = header.getBreadCrumbTitle(getResources());
1117 if (title == null) title = header.getTitle(getResources());
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001118 if (title == null) title = getTitle();
Dianne Hackborn50ed8292010-12-03 12:30:21 -08001119 showBreadCrumbs(title, header.getBreadCrumbShortTitle(getResources()));
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001120 } else {
1121 showBreadCrumbs(getTitle(), null);
1122 }
1123 }
1124
Amith Yamasanif5cbaed2010-10-27 16:14:20 -07001125 private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001126 getFragmentManager().popBackStack(BACK_STACK_PREFS,
1127 FragmentManager.POP_BACK_STACK_INCLUSIVE);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001128 Fragment f = Fragment.instantiate(this, fragmentName, args);
Dianne Hackborn48e7b452011-01-17 12:28:35 -08001129 FragmentTransaction transaction = getFragmentManager().beginTransaction();
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001130 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
Chet Haase9ff82bf2010-10-05 14:30:51 -07001131 transaction.replace(com.android.internal.R.id.prefs, f);
Dianne Hackborncf407ad2011-03-11 13:17:57 -08001132 transaction.commitAllowingStateLoss();
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001133 }
1134
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001135 /**
1136 * When in two-pane mode, switch the fragment pane to show the given
1137 * preference fragment.
1138 *
1139 * @param fragmentName The name of the fragment to display.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001140 * @param args Optional arguments to supply to the fragment.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001141 */
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001142 public void switchToHeader(String fragmentName, Bundle args) {
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001143 setSelectedHeader(null);
Amith Yamasanif5cbaed2010-10-27 16:14:20 -07001144 switchToHeaderInner(fragmentName, args, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 }
1146
Andrew Stadleraa904f42010-09-02 14:50:08 -07001147 /**
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001148 * When in two-pane mode, switch to the fragment pane to show the given
1149 * preference fragment.
1150 *
1151 * @param header The new header to display.
1152 */
1153 public void switchToHeader(Header header) {
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001154 if (mCurHeader == header) {
1155 // This is the header we are currently displaying. Just make sure
1156 // to pop the stack up to its root state.
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001157 getFragmentManager().popBackStack(BACK_STACK_PREFS,
1158 FragmentManager.POP_BACK_STACK_INCLUSIVE);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001159 } else {
1160 int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
1161 switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
1162 setSelectedHeader(header);
1163 }
Dianne Hackborna21e3da2010-09-12 19:27:46 -07001164 }
1165
1166 Header findBestMatchingHeader(Header cur, ArrayList<Header> from) {
1167 ArrayList<Header> matches = new ArrayList<Header>();
1168 for (int j=0; j<from.size(); j++) {
1169 Header oh = from.get(j);
1170 if (cur == oh || (cur.id != HEADER_ID_UNDEFINED && cur.id == oh.id)) {
1171 // Must be this one.
1172 matches.clear();
1173 matches.add(oh);
1174 break;
1175 }
1176 if (cur.fragment != null) {
1177 if (cur.fragment.equals(oh.fragment)) {
1178 matches.add(oh);
1179 }
1180 } else if (cur.intent != null) {
1181 if (cur.intent.equals(oh.intent)) {
1182 matches.add(oh);
1183 }
1184 } else if (cur.title != null) {
1185 if (cur.title.equals(oh.title)) {
1186 matches.add(oh);
1187 }
1188 }
1189 }
1190 final int NM = matches.size();
1191 if (NM == 1) {
1192 return matches.get(0);
1193 } else if (NM > 1) {
1194 for (int j=0; j<NM; j++) {
1195 Header oh = matches.get(j);
1196 if (cur.fragmentArguments != null &&
1197 cur.fragmentArguments.equals(oh.fragmentArguments)) {
1198 return oh;
1199 }
1200 if (cur.extras != null && cur.extras.equals(oh.extras)) {
1201 return oh;
1202 }
1203 if (cur.title != null && cur.title.equals(oh.title)) {
1204 return oh;
1205 }
1206 }
1207 }
1208 return null;
1209 }
1210
1211 /**
Andrew Stadleraa904f42010-09-02 14:50:08 -07001212 * Start a new fragment.
1213 *
1214 * @param fragment The fragment to start
1215 * @param push If true, the current fragment will be pushed onto the back stack. If false,
1216 * the current fragment will be replaced.
1217 */
1218 public void startPreferenceFragment(Fragment fragment, boolean push) {
Dianne Hackborn48e7b452011-01-17 12:28:35 -08001219 FragmentTransaction transaction = getFragmentManager().beginTransaction();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001220 transaction.replace(com.android.internal.R.id.prefs, fragment);
Andrew Stadleraa904f42010-09-02 14:50:08 -07001221 if (push) {
Chet Haase9ff82bf2010-10-05 14:30:51 -07001222 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
Andrew Stadleraa904f42010-09-02 14:50:08 -07001223 transaction.addToBackStack(BACK_STACK_PREFS);
Chet Haase9ff82bf2010-10-05 14:30:51 -07001224 } else {
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001225 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
Andrew Stadleraa904f42010-09-02 14:50:08 -07001226 }
Dianne Hackborncf407ad2011-03-11 13:17:57 -08001227 transaction.commitAllowingStateLoss();
Andrew Stadleraa904f42010-09-02 14:50:08 -07001228 }
1229
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001230 /**
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001231 * Start a new fragment containing a preference panel. If the prefences
1232 * are being displayed in multi-pane mode, the given fragment class will
1233 * be instantiated and placed in the appropriate pane. If running in
1234 * single-pane mode, a new activity will be launched in which to show the
1235 * fragment.
1236 *
1237 * @param fragmentClass Full name of the class implementing the fragment.
1238 * @param args Any desired arguments to supply to the fragment.
1239 * @param titleRes Optional resource identifier of the title of this
1240 * fragment.
1241 * @param titleText Optional text of the title of this fragment.
1242 * @param resultTo Optional fragment that result data should be sent to.
1243 * If non-null, resultTo.onActivityResult() will be called when this
1244 * preference panel is done. The launched panel must use
1245 * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
1246 * @param resultRequestCode If resultTo is non-null, this is the caller's
1247 * request code to be received with the resut.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001248 */
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001249 public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
1250 CharSequence titleText, Fragment resultTo, int resultRequestCode) {
1251 if (mSinglePane) {
Dianne Hackborne72f2372011-03-16 10:43:18 -07001252 startWithFragment(fragmentClass, args, resultTo, resultRequestCode, titleRes, 0);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001253 } else {
1254 Fragment f = Fragment.instantiate(this, fragmentClass, args);
1255 if (resultTo != null) {
1256 f.setTargetFragment(resultTo, resultRequestCode);
1257 }
Dianne Hackborn48e7b452011-01-17 12:28:35 -08001258 FragmentTransaction transaction = getFragmentManager().beginTransaction();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001259 transaction.replace(com.android.internal.R.id.prefs, f);
1260 if (titleRes != 0) {
1261 transaction.setBreadCrumbTitle(titleRes);
1262 } else if (titleText != null) {
1263 transaction.setBreadCrumbTitle(titleText);
1264 }
1265 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
1266 transaction.addToBackStack(BACK_STACK_PREFS);
Dianne Hackborncf407ad2011-03-11 13:17:57 -08001267 transaction.commitAllowingStateLoss();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001268 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001269 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001270
1271 /**
1272 * Called by a preference panel fragment to finish itself.
1273 *
1274 * @param caller The fragment that is asking to be finished.
1275 * @param resultCode Optional result code to send back to the original
1276 * launching fragment.
1277 * @param resultData Optional result data to send back to the original
1278 * launching fragment.
1279 */
1280 public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
1281 if (mSinglePane) {
1282 setResult(resultCode, resultData);
1283 finish();
1284 } else {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001285 // XXX be smarter about popping the stack.
1286 onBackPressed();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001287 if (caller != null) {
1288 if (caller.getTargetFragment() != null) {
1289 caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
1290 resultCode, resultData);
1291 }
1292 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001293 }
1294 }
1295
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001296 @Override
1297 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
Dianne Hackborne72f2372011-03-16 10:43:18 -07001298 startPreferencePanel(pref.getFragment(), pref.getExtras(), pref.getTitleRes(),
1299 pref.getTitle(), null, 0);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001300 return true;
1301 }
1302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 /**
1304 * Posts a message to bind the preferences to the list view.
1305 * <p>
1306 * Binding late is preferred as any custom preference types created in
1307 * {@link #onCreate(Bundle)} are able to have their views recycled.
1308 */
1309 private void postBindPreferences() {
1310 if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
1311 mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
1312 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 private void bindPreferences() {
1315 final PreferenceScreen preferenceScreen = getPreferenceScreen();
1316 if (preferenceScreen != null) {
1317 preferenceScreen.bind(getListView());
Adam Powelle7fea452010-03-18 14:51:39 -07001318 if (mSavedInstanceState != null) {
1319 super.onRestoreInstanceState(mSavedInstanceState);
1320 mSavedInstanceState = null;
1321 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 }
1323 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 * Returns the {@link PreferenceManager} used by this activity.
1327 * @return The {@link PreferenceManager}.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001328 *
1329 * @deprecated This function is not relevant for a modern fragment-based
1330 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001332 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 public PreferenceManager getPreferenceManager() {
1334 return mPreferenceManager;
1335 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 private void requirePreferenceManager() {
1338 if (mPreferenceManager == null) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001339 if (mAdapter == null) {
1340 throw new RuntimeException("This should be called after super.onCreate.");
1341 }
1342 throw new RuntimeException(
1343 "Modern two-pane PreferenceActivity requires use of a PreferenceFragment");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 }
1345 }
1346
1347 /**
1348 * Sets the root of the preference hierarchy that this activity is showing.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001349 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001351 *
1352 * @deprecated This function is not relevant for a modern fragment-based
1353 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001355 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001357 requirePreferenceManager();
1358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
1360 postBindPreferences();
1361 CharSequence title = getPreferenceScreen().getTitle();
1362 // Set the title of the activity
1363 if (title != null) {
1364 setTitle(title);
1365 }
1366 }
1367 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 /**
1370 * Gets the root of the preference hierarchy that this activity is showing.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001371 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 * @return The {@link PreferenceScreen} that is the root of the preference
1373 * hierarchy.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001374 *
1375 * @deprecated This function is not relevant for a modern fragment-based
1376 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001378 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 public PreferenceScreen getPreferenceScreen() {
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001380 if (mPreferenceManager != null) {
1381 return mPreferenceManager.getPreferenceScreen();
1382 }
1383 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 /**
1387 * Adds preferences from activities that match the given {@link Intent}.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001388 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 * @param intent The {@link Intent} to query activities.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001390 *
1391 * @deprecated This function is not relevant for a modern fragment-based
1392 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001394 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 public void addPreferencesFromIntent(Intent intent) {
1396 requirePreferenceManager();
Freeman Ng19ea2e02010-03-25 15:09:00 -07001397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
1399 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 /**
1402 * Inflates the given XML resource and adds the preference hierarchy to the current
1403 * preference hierarchy.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001404 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 * @param preferencesResId The XML resource ID to inflate.
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001406 *
1407 * @deprecated This function is not relevant for a modern fragment-based
1408 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001410 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 public void addPreferencesFromResource(int preferencesResId) {
1412 requirePreferenceManager();
Freeman Ng19ea2e02010-03-25 15:09:00 -07001413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 setPreferenceScreen(mPreferenceManager.inflateFromResource(this, preferencesResId,
1415 getPreferenceScreen()));
1416 }
1417
1418 /**
1419 * {@inheritDoc}
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001420 *
1421 * @deprecated This function is not relevant for a modern fragment-based
1422 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001424 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
1426 return false;
1427 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 /**
1430 * Finds a {@link Preference} based on its key.
Freeman Ng19ea2e02010-03-25 15:09:00 -07001431 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 * @param key The key of the preference to retrieve.
1433 * @return The {@link Preference} with the key, or null.
1434 * @see PreferenceGroup#findPreference(CharSequence)
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001435 *
1436 * @deprecated This function is not relevant for a modern fragment-based
1437 * PreferenceActivity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 */
Dianne Hackbornb1ad5972010-08-02 17:30:33 -07001439 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 public Preference findPreference(CharSequence key) {
Freeman Ng19ea2e02010-03-25 15:09:00 -07001441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 if (mPreferenceManager == null) {
1443 return null;
1444 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 return mPreferenceManager.findPreference(key);
1447 }
1448
1449 @Override
1450 protected void onNewIntent(Intent intent) {
1451 if (mPreferenceManager != null) {
1452 mPreferenceManager.dispatchNewIntent(intent);
1453 }
1454 }
Freeman Ng19ea2e02010-03-25 15:09:00 -07001455
1456 // give subclasses access to the Next button
1457 /** @hide */
1458 protected boolean hasNextButton() {
1459 return mNextButton != null;
1460 }
1461 /** @hide */
1462 protected Button getNextButton() {
1463 return mNextButton;
1464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465}