PreferenceFragment.java revision 35d7b89b9f6151083001e3bae315a8e98882741f
1b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/*
2b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * Copyright (C) 2010 The Android Open Source Project
3b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
4b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * Licensed under the Apache License, Version 2.0 (the "License");
5b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * you may not use this file except in compliance with the License.
6b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * You may obtain a copy of the License at
7b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
8b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *      http://www.apache.org/licenses/LICENSE-2.0
9b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * Unless required by applicable law or agreed to in writing, software
11b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * distributed under the License is distributed on an "AS IS" BASIS,
12b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * See the License for the specific language governing permissions and
14b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * limitations under the License.
15b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov */
16b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
17b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovpackage android.preference;
18b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
19b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.app.Activity;
20b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.app.Fragment;
21b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.content.Intent;
22b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.content.SharedPreferences;
23b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.os.Bundle;
24b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.os.Handler;
25b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.os.Message;
26b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.view.KeyEvent;
27b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.view.LayoutInflater;
28b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.view.View;
29b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovimport android.view.ViewGroup;
30436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovimport android.view.View.OnKeyListener;
31436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovimport android.widget.ListView;
32436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
33436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/**
34eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov * Shows a hierarchy of {@link Preference} objects as
35eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov * lists. These preferences will
36b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * automatically save to {@link SharedPreferences} as the user interacts with
37b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * them. To retrieve an instance of {@link SharedPreferences} that the
38b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * preference hierarchy in this fragment will use, call
39b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * {@link PreferenceManager#getDefaultSharedPreferences(android.content.Context)}
40b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * with a context in the same package as this fragment.
41b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>
42b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * Furthermore, the preferences shown will follow the visual style of system
43663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng * preferences. It is easy to create a hierarchy of preferences (that can be
44b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * shown on multiple screens) via XML. For these reasons, it is recommended to
45b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * use this fragment (as a superclass) to deal with preferences in applications.
46b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>
47663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng * A {@link PreferenceScreen} object should be at the top of the preference
48b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * hierarchy. Furthermore, subsequent {@link PreferenceScreen} in the hierarchy
49663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng * denote a screen break--that is the preferences contained within subsequent
50663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng * {@link PreferenceScreen} should be shown on another screen. The preference
51663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng * framework handles showing these other screens from the preference hierarchy.
52b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>
53663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng * The preference hierarchy can be formed in multiple ways:
54b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <li> From an XML file specifying the hierarchy
55b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <li> From different {@link Activity Activities} that each specify its own
56b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * preferences in an XML file via {@link Activity} meta-data
57b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <li> From an object hierarchy rooted with {@link PreferenceScreen}
58b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>
59b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * To inflate from XML, use the {@link #addPreferencesFromResource(int)}. The
60b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * root element should be a {@link PreferenceScreen}. Subsequent elements can point
61436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov * to actual {@link Preference} subclasses. As mentioned above, subsequent
62b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * {@link PreferenceScreen} in the hierarchy will result in the screen break.
63b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>
64b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * To specify an {@link Intent} to query {@link Activity Activities} that each
65b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * have preferences, use {@link #addPreferencesFromIntent}. Each
66b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * {@link Activity} can specify meta-data in the manifest (via the key
67b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * {@link PreferenceManager#METADATA_KEY_PREFERENCES}) that points to an XML
68b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * resource. These XML resources will be inflated into a single preference
69b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * hierarchy and shown by this fragment.
70b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>
71b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * To specify an object hierarchy rooted with {@link PreferenceScreen}, use
72b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * {@link #setPreferenceScreen(PreferenceScreen)}.
73b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>
74b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * As a convenience, this fragment implements a click listener for any
75b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * preference in the current hierarchy, see
76b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * {@link #onPreferenceTreeClick(PreferenceScreen, Preference)}.
77b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
78b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <div class="special reference">
79b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <h3>Developer Guides</h3>
80b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>For information about using {@code PreferenceFragment},
81b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * read the <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>
82b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * guide.</p>
83b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * </div>
84b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
85b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <a name="SampleCode"></a>
86b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <h3>Sample Code</h3>
87b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
88b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>The following sample code shows a simple preference fragment that is
89b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * populated from a resource.  The resource it loads is:</p>
90b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
91b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * {@sample development/samples/ApiDemos/res/xml/preferences.xml preferences}
92b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
93b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * <p>The fragment implementation itself simply populates the preferences
94b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * when created.  Note that the preferences framework takes care of loading
95b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * the current values out of the app preferences and writing them when changed:</p>
96b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
97b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * {@sample development/samples/ApiDemos/src/com/example/android/apis/preference/FragmentPreferences.java
98b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *      fragment}
99b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov *
100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * @see Preference
101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * @see PreferenceScreen
102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov */
103436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovpublic abstract class PreferenceFragment extends Fragment implements
104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        PreferenceManager.OnPreferenceTreeClickListener {
105b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    private static final String PREFERENCES_TAG = "android:preferences";
107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    private PreferenceManager mPreferenceManager;
109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    private ListView mList;
110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    private boolean mHavePrefs;
111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    private boolean mInitDone;
112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
113436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    /**
114436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     * The starting request code given out to preference framework.
115436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     */
116436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    private static final int FIRST_REQUEST_CODE = 100;
117436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
118436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    private static final int MSG_BIND_PREFERENCES = 1;
119436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    private Handler mHandler = new Handler() {
120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        @Override
121436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        public void handleMessage(Message msg) {
122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            switch (msg.what) {
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                case MSG_BIND_PREFERENCES:
125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    bindPreferences();
126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    break;
127436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            }
128436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        }
129436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    };
130436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
131436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    final private Runnable mRequestFocus = new Runnable() {
132436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        public void run() {
133436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            mList.focusableViewAvailable(mList);
134436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        }
135436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    };
136436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
137436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    /**
138436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     * Interface that PreferenceFragment's containing activity should
139436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     * implement to be able to process preference items that wish to
140436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     * switch to a new fragment.
141436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     */
142436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    public interface OnPreferenceStartFragmentCallback {
143436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        /**
144436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         * Called when the user has clicked on a Preference that has
145436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         * a fragment class name associated with it.  The implementation
146436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         * to should instantiate and switch to an instance of the given
147436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         * fragment.
148436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         */
149436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref);
150436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    }
151436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
152eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    @Override
153eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    public void onCreate(Bundle savedInstanceState) {
154eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        super.onCreate(savedInstanceState);
155eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        mPreferenceManager = new PreferenceManager(getActivity(), FIRST_REQUEST_CODE);
156eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        mPreferenceManager.setFragment(this);
157eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    }
158eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
159eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    @Override
160eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    public View onCreateView(LayoutInflater inflater, ViewGroup container,
161eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            Bundle savedInstanceState) {
162eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        return inflater.inflate(com.android.internal.R.layout.preference_list_fragment, container,
163eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                false);
164eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    }
165eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
166eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    @Override
167eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    public void onActivityCreated(Bundle savedInstanceState) {
168eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        super.onActivityCreated(savedInstanceState);
169eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
170eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        if (mHavePrefs) {
171eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            bindPreferences();
172eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        }
173eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
174eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        mInitDone = true;
175eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
176b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (savedInstanceState != null) {
177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);
178b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            if (container != null) {
179b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                final PreferenceScreen preferenceScreen = getPreferenceScreen();
180b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                if (preferenceScreen != null) {
181b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    preferenceScreen.restoreHierarchyState(container);
182b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                }
183b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
184436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        }
185b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
186b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    @Override
188436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    public void onStart() {
189436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        super.onStart();
190436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        mPreferenceManager.setOnPreferenceTreeClickListener(this);
191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
193b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    @Override
194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public void onStop() {
195b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        super.onStop();
196b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        mPreferenceManager.dispatchActivityStop();
197b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        mPreferenceManager.setOnPreferenceTreeClickListener(null);
198b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
199b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    @Override
201436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    public void onDestroyView() {
202436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        mList = null;
203b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        mHandler.removeCallbacks(mRequestFocus);
204b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        mHandler.removeMessages(MSG_BIND_PREFERENCES);
205b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        super.onDestroyView();
206b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
207b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
208b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    @Override
209b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public void onDestroy() {
210b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        super.onDestroy();
211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        mPreferenceManager.dispatchActivityDestroy();
212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
213b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    @Override
215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public void onSaveInstanceState(Bundle outState) {
216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        super.onSaveInstanceState(outState);
217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        final PreferenceScreen preferenceScreen = getPreferenceScreen();
219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (preferenceScreen != null) {
220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            Bundle container = new Bundle();
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            preferenceScreen.saveHierarchyState(container);
222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            outState.putBundle(PREFERENCES_TAG, container);
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
225436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    @Override
227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public void onActivityResult(int requestCode, int resultCode, Intent data) {
228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        super.onActivityResult(requestCode, resultCode, data);
229eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
230436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        mPreferenceManager.dispatchActivityResult(requestCode, resultCode, data);
231436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    }
232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    /**
234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * Returns the {@link PreferenceManager} used by this fragment.
235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * @return The {@link PreferenceManager}.
236436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     */
237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public PreferenceManager getPreferenceManager() {
238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        return mPreferenceManager;
239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
240436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
241b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    /**
242663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng     * Sets the root of the preference hierarchy that this fragment is showing.
243663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng     *
244436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     */
246436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
247b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (mPreferenceManager.setPreferences(preferenceScreen) && preferenceScreen != null) {
248eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            mHavePrefs = true;
249eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            if (mInitDone) {
250b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                postBindPreferences();
251b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
252b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
253b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
254b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
255b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    /**
256b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * Gets the root of the preference hierarchy that this fragment is showing.
257b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     *
258b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * @return The {@link PreferenceScreen} that is the root of the preference
259436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     *         hierarchy.
260eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov     */
261b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public PreferenceScreen getPreferenceScreen() {
262b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        return mPreferenceManager.getPreferenceScreen();
263b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
264b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
265b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    /**
266b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * Adds preferences from activities that match the given {@link Intent}.
267436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     *
268b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * @param intent The {@link Intent} to query activities.
269b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     */
270b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public void addPreferencesFromIntent(Intent intent) {
271b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        requirePreferenceManager();
272b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
273436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        setPreferenceScreen(mPreferenceManager.inflateFromIntent(intent, getPreferenceScreen()));
274436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    }
275436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
276b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    /**
277b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * Inflates the given XML resource and adds the preference hierarchy to the current
278b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * preference hierarchy.
279b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     *
280436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     * @param preferencesResId The XML resource ID to inflate.
281b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     */
282b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public void addPreferencesFromResource(int preferencesResId) {
283b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        requirePreferenceManager();
284436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
285b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        setPreferenceScreen(mPreferenceManager.inflateFromResource(getActivity(),
286b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                preferencesResId, getPreferenceScreen()));
287436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    }
288436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
289436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    /**
290436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     * {@inheritDoc}
291436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     */
292b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
293b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            Preference preference) {
294b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (preference.getFragment() != null &&
295b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                getActivity() instanceof OnPreferenceStartFragmentCallback) {
296436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            return ((OnPreferenceStartFragmentCallback)getActivity()).onPreferenceStartFragment(
297b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    this, preference);
298b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
299b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        return false;
300b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
301436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
302b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    /**
303b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * Finds a {@link Preference} based on its key.
304b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     *
305b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * @param key The key of the preference to retrieve.
306436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov     * @return The {@link Preference} with the key, or null.
307b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     * @see PreferenceGroup#findPreference(CharSequence)
308b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     */
309b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public Preference findPreference(CharSequence key) {
310b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (mPreferenceManager == null) {
311b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            return null;
312eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        }
313eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        return mPreferenceManager.findPreference(key);
314eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    }
315eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
316eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    private void requirePreferenceManager() {
317eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        if (mPreferenceManager == null) {
318eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            throw new RuntimeException("This should be called after super.onCreate.");
319eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        }
320eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    }
321eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
322eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    private void postBindPreferences() {
323eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
324eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
325eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    }
326eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
327eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    private void bindPreferences() {
328eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        final PreferenceScreen preferenceScreen = getPreferenceScreen();
329eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        if (preferenceScreen != null) {
330eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            preferenceScreen.bind(getListView());
331eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        }
332eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    }
333eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
334eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    /** @hide */
335eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    public ListView getListView() {
336eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        ensureList();
337eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov        return mList;
338b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    }
339b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
340b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    /** @hide */
341b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov    public boolean hasListView() {
342b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (mList != null) {
343b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            return true;
344b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
345b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        View root = getView();
346b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (root == null) {
347eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            return false;
348b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
349b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        View rawListView = root.findViewById(android.R.id.list);
350b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (!(rawListView instanceof ListView)) {
351b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            return false;
352b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
353b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        mList = (ListView)rawListView;
354b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (mList == null) {
355b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            return false;
356b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
357436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        return true;
358436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    }
359436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
360436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov    private void ensureList() {
361436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        if (mList != null) {
362b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            return;
363b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
364b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        View root = getView();
365b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (root == null) {
366b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            throw new IllegalStateException("Content view not yet created");
367b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
368b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        View rawListView = root.findViewById(android.R.id.list);
369b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        if (!(rawListView instanceof ListView)) {
370436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            throw new RuntimeException(
371436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                    "Content has view with id attribute 'android.R.id.list' "
372b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    + "that is not a ListView class");
373b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        }
374b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        mList = (ListView)rawListView;
375663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        if (mList == null) {
376663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng            throw new RuntimeException(
377663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                    "Your content must have a ListView whose id attribute is " +
378663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng                    "'android.R.id.list'");
379663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        }
380663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        mList.setOnKeyListener(mListOnKeyListener);
381663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        mHandler.post(mRequestFocus);
382663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng    }
383663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
384663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng    private OnKeyListener mListOnKeyListener = new OnKeyListener() {
385663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
386663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng        @Override
387b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        public boolean onKey(View v, int keyCode, KeyEvent event) {
388b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            Object selectedItem = mList.getSelectedItem();
389b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            if (selectedItem instanceof Preference) {
390eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                View selectedView = mList.getSelectedView();
391eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                return ((Preference)selectedItem).onKey(
392eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov                        selectedView, keyCode, event);
393b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            }
394b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            return false;
395436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        }
396eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov
397eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov    };
398436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
399436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov