mobile/android/base/background/preferences/PreferenceFragment.java

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:345c02c94f4c
1 /*
2 * Copyright (C) 2013 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
17 package org.mozilla.gecko.background.preferences;
18
19 import org.mozilla.gecko.R;
20
21 import android.content.Intent;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.preference.Preference;
26 import android.preference.PreferenceGroup;
27 import android.preference.PreferenceManager;
28 import android.preference.PreferenceScreen;
29 import android.support.v4.app.Fragment;
30 import android.view.KeyEvent;
31 import android.view.LayoutInflater;
32 import android.view.View;
33 import android.view.View.OnKeyListener;
34 import android.view.ViewGroup;
35 import android.widget.ListView;
36
37 public abstract class PreferenceFragment extends Fragment implements PreferenceManagerCompat.OnPreferenceTreeClickListener {
38 private static final String PREFERENCES_TAG = "android:preferences";
39
40 private PreferenceManager mPreferenceManager;
41 private ListView mList;
42 private boolean mHavePrefs;
43 private boolean mInitDone;
44
45 /**
46 * The starting request code given out to preference framework.
47 */
48 private static final int FIRST_REQUEST_CODE = 100;
49
50 private static final int MSG_BIND_PREFERENCES = 1;
51
52 // This triggers "This Handler class should be static or leaks might occur".
53 // The issue is that the Handler references the Fragment; messages targeting
54 // the Handler reference it; and if such messages are long lived, the Fragment
55 // cannot be GCed. This is not an issue for us; our messages are short-lived.
56 private Handler mHandler = new Handler() {
57 @Override
58 public void handleMessage(Message msg) {
59 switch (msg.what) {
60
61 case MSG_BIND_PREFERENCES:
62 bindPreferences();
63 break;
64 }
65 }
66 };
67
68 final private Runnable mRequestFocus = new Runnable() {
69 @Override
70 public void run() {
71 mList.focusableViewAvailable(mList);
72 }
73 };
74
75 /**
76 * Interface that PreferenceFragment's containing activity should
77 * implement to be able to process preference items that wish to
78 * switch to a new fragment.
79 */
80 public interface OnPreferenceStartFragmentCallback {
81 /**
82 * Called when the user has clicked on a Preference that has
83 * a fragment class name associated with it. The implementation
84 * to should instantiate and switch to an instance of the given
85 * fragment.
86 */
87 boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref);
88 }
89
90 @Override
91 public void onCreate(Bundle paramBundle) {
92 super.onCreate(paramBundle);
93 mPreferenceManager = PreferenceManagerCompat.newInstance(getActivity(), FIRST_REQUEST_CODE);
94 PreferenceManagerCompat.setFragment(mPreferenceManager, this);
95 }
96
97 @Override
98 public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) {
99 return paramLayoutInflater.inflate(R.layout.fxaccount_preference_list_fragment, paramViewGroup,
100 false);
101 }
102
103 @Override
104 public void onActivityCreated(Bundle savedInstanceState) {
105 super.onActivityCreated(savedInstanceState);
106
107 if (mHavePrefs) {
108 bindPreferences();
109 }
110
111 mInitDone = true;
112
113 if (savedInstanceState != null) {
114 Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);
115 if (container != null) {
116 final PreferenceScreen preferenceScreen = getPreferenceScreen();
117 if (preferenceScreen != null) {
118 preferenceScreen.restoreHierarchyState(container);
119 }
120 }
121 }
122 }
123
124 @Override
125 public void onStart() {
126 super.onStart();
127 PreferenceManagerCompat.setOnPreferenceTreeClickListener(mPreferenceManager, this);
128 }
129
130 @Override
131 public void onStop() {
132 super.onStop();
133 PreferenceManagerCompat.dispatchActivityStop(mPreferenceManager);
134 PreferenceManagerCompat.setOnPreferenceTreeClickListener(mPreferenceManager, null);
135 }
136
137 @Override
138 public void onDestroyView() {
139 mList = null;
140 mHandler.removeCallbacks(mRequestFocus);
141 mHandler.removeMessages(MSG_BIND_PREFERENCES);
142 super.onDestroyView();
143 }
144
145 @Override
146 public void onDestroy() {
147 super.onDestroy();
148 PreferenceManagerCompat.dispatchActivityDestroy(mPreferenceManager);
149 }
150
151 @Override
152 public void onSaveInstanceState(Bundle outState) {
153 super.onSaveInstanceState(outState);
154
155 final PreferenceScreen preferenceScreen = getPreferenceScreen();
156 if (preferenceScreen != null) {
157 Bundle container = new Bundle();
158 preferenceScreen.saveHierarchyState(container);
159 outState.putBundle(PREFERENCES_TAG, container);
160 }
161 }
162
163 @Override
164 public void onActivityResult(int requestCode, int resultCode, Intent data) {
165 super.onActivityResult(requestCode, resultCode, data);
166
167 PreferenceManagerCompat.dispatchActivityResult(mPreferenceManager, requestCode, resultCode, data);
168 }
169
170 /**
171 * Returns the {@link PreferenceManager} used by this fragment.
172 * @return The {@link PreferenceManager}.
173 */
174 public PreferenceManager getPreferenceManager() {
175 return mPreferenceManager;
176 }
177
178 /**
179 * Sets the root of the preference hierarchy that this fragment is showing.
180 *
181 * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
182 */
183 public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
184 if (PreferenceManagerCompat.setPreferences(mPreferenceManager, preferenceScreen) && preferenceScreen != null) {
185 mHavePrefs = true;
186 if (mInitDone) {
187 postBindPreferences();
188 }
189 }
190 }
191
192 /**
193 * Gets the root of the preference hierarchy that this fragment is showing.
194 *
195 * @return The {@link PreferenceScreen} that is the root of the preference
196 * hierarchy.
197 */
198 public PreferenceScreen getPreferenceScreen() {
199 return PreferenceManagerCompat.getPreferenceScreen(mPreferenceManager);
200 }
201
202 /**
203 * Adds preferences from activities that match the given {@link Intent}.
204 *
205 * @param intent The {@link Intent} to query activities.
206 */
207 public void addPreferencesFromIntent(Intent intent) {
208 requirePreferenceManager();
209
210 setPreferenceScreen(PreferenceManagerCompat.inflateFromIntent(mPreferenceManager, intent, getPreferenceScreen()));
211 }
212
213 /**
214 * Inflates the given XML resource and adds the preference hierarchy to the current
215 * preference hierarchy.
216 *
217 * @param preferencesResId The XML resource ID to inflate.
218 */
219 public void addPreferencesFromResource(int preferencesResId) {
220 requirePreferenceManager();
221
222 setPreferenceScreen(PreferenceManagerCompat.inflateFromResource(mPreferenceManager, getActivity(),
223 preferencesResId, getPreferenceScreen()));
224 }
225
226 /**
227 * {@inheritDoc}
228 */
229 @Override
230 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
231 Preference preference) {
232 //if (preference.getFragment() != null &&
233 if (
234 getActivity() instanceof OnPreferenceStartFragmentCallback) {
235 return ((OnPreferenceStartFragmentCallback)getActivity()).onPreferenceStartFragment(
236 this, preference);
237 }
238 return false;
239 }
240
241 /**
242 * Finds a {@link Preference} based on its key.
243 *
244 * @param key The key of the preference to retrieve.
245 * @return The {@link Preference} with the key, or null.
246 * @see PreferenceGroup#findPreference(CharSequence)
247 */
248 public Preference findPreference(CharSequence key) {
249 if (mPreferenceManager == null) {
250 return null;
251 }
252 return mPreferenceManager.findPreference(key);
253 }
254
255 private void requirePreferenceManager() {
256 if (mPreferenceManager == null) {
257 throw new RuntimeException("This should be called after super.onCreate.");
258 }
259 }
260
261 private void postBindPreferences() {
262 if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) return;
263 mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
264 }
265
266 private void bindPreferences() {
267 final PreferenceScreen preferenceScreen = getPreferenceScreen();
268 if (preferenceScreen != null) {
269 preferenceScreen.bind(getListView());
270 }
271 }
272
273 public ListView getListView() {
274 ensureList();
275 return mList;
276 }
277
278 private void ensureList() {
279 if (mList != null) {
280 return;
281 }
282 View root = getView();
283 if (root == null) {
284 throw new IllegalStateException("Content view not yet created");
285 }
286 View rawListView = root.findViewById(android.R.id.list);
287 if (!(rawListView instanceof ListView)) {
288 throw new RuntimeException(
289 "Content has view with id attribute 'android.R.id.list' "
290 + "that is not a ListView class");
291 }
292 mList = (ListView)rawListView;
293 if (mList == null) {
294 throw new RuntimeException(
295 "Your content must have a ListView whose id attribute is " +
296 "'android.R.id.list'");
297 }
298 mList.setOnKeyListener(mListOnKeyListener);
299 mHandler.post(mRequestFocus);
300 }
301
302 private OnKeyListener mListOnKeyListener = new OnKeyListener() {
303
304 @Override
305 public boolean onKey(View v, int keyCode, KeyEvent event) {
306 Object selectedItem = mList.getSelectedItem();
307 if (selectedItem instanceof Preference) {
308 @SuppressWarnings("unused")
309 View selectedView = mList.getSelectedView();
310 //return ((Preference)selectedItem).onKey(
311 // selectedView, keyCode, event);
312 return false;
313 }
314 return false;
315 }
316
317 };
318 }

mercurial