blob: f41561e869fb79f87fa1ba6f8d34fd193221020a [file] [log] [blame]
Amith Yamasanid7993472010-08-18 13:59:28 -07001/*
2 * Copyright (C) 2010 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 com.android.settings;
18
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -070019import android.app.Activity;
Amith Yamasanid7993472010-08-18 13:59:28 -070020import android.app.Dialog;
21import android.app.DialogFragment;
Daisuke Miyakawab5647c52010-09-10 18:04:02 -070022import android.app.Fragment;
Amith Yamasanid7993472010-08-18 13:59:28 -070023import android.content.ContentResolver;
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -070024import android.content.Intent;
Amith Yamasanid7993472010-08-18 13:59:28 -070025import android.content.pm.PackageManager;
26import android.content.res.Resources;
27import android.os.Bundle;
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -070028import android.preference.PreferenceActivity;
Amith Yamasanid7993472010-08-18 13:59:28 -070029import android.preference.PreferenceFragment;
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -070030import android.text.TextUtils;
Amith Yamasanid7993472010-08-18 13:59:28 -070031import android.util.Log;
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -070032import android.view.View;
33import android.view.View.OnClickListener;
34import android.widget.Button;
Amith Yamasanid7993472010-08-18 13:59:28 -070035
Daisuke Miyakawaf58090d2010-09-12 17:27:33 -070036/**
37 * Letting the class, assumed to be Fragment, create a Dialog on it. Should be useful
38 * you want to utilize some capability in {@link SettingsPreferenceFragment} but don't want
39 * the class inherit the class itself (See {@link ProxySelector} for example).
40 */
Daisuke Miyakawa21c1abc2010-09-12 15:42:56 -070041interface DialogCreatable {
42 public Dialog onCreateDialog(int dialogId);
43}
44
Amith Yamasanid7993472010-08-18 13:59:28 -070045/**
46 * Base class for Settings fragments, with some helper functions and dialog management.
47 */
Daisuke Miyakawa21c1abc2010-09-12 15:42:56 -070048public class SettingsPreferenceFragment extends PreferenceFragment
49 implements DialogCreatable {
Amith Yamasanid7993472010-08-18 13:59:28 -070050
51 private static final String TAG = "SettingsPreferenceFragment";
52
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -070053 // Originally from PreferenceActivity.
54 private static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
55 private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip";
56 private static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
57 private static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
58
Amith Yamasanid7993472010-08-18 13:59:28 -070059 private SettingsDialogFragment mDialogFragment;
60
61 private OnStateListener mOnStateListener;
Daisuke Miyakawab5647c52010-09-10 18:04:02 -070062 private FragmentStarter mFragmentStarter;
63
64 private int mResultCode = Activity.RESULT_CANCELED;
65 private Intent mResultData;
Amith Yamasanid7993472010-08-18 13:59:28 -070066
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -070067 private Button mNextButton;
68
Amith Yamasanib61cf512010-09-12 08:17:50 -070069 private boolean mReportedCreation;
70
Amith Yamasanid7993472010-08-18 13:59:28 -070071 interface OnStateListener {
72
73 void onCreated(SettingsPreferenceFragment fragment);
74
75 void onDestroyed(SettingsPreferenceFragment fragment);
76 }
77
78 public void setOnStateListener(OnStateListener listener) {
79 mOnStateListener = listener;
80 }
81
Daisuke Miyakawab5647c52010-09-10 18:04:02 -070082 /**
83 * Letting the class, assumed to be Fragment, start another Fragment object.
84 * The target Fragment object is stored in the caller Fragment using
85 * {@link Fragment#setTargetFragment(Fragment, int)}. The caller
86 * is able to obtain result code and result data via
87 * {@link SettingsPreferenceFragment#getResultCode()} and
88 * {@link SettingsPreferenceFragment#getResultData()} accordingly.
89 */
90 interface FragmentStarter {
91 public boolean startFragment(
92 Fragment caller, String fragmentClass, int requestCode, Bundle extras);
93 }
94
95 public void setFragmentStarter(FragmentStarter starter) {
96 mFragmentStarter = starter;
97 }
98
99 @Override
100 public void onResume() {
101 super.onResume();
102
103 final Fragment f = getTargetFragment();
104 final int requestCode = getTargetRequestCode();
105
106 // TargetFragment becomes invalid when this object is resumed. Notify it to
107 // FragmentManager. Without this code, FragmentManager wrongly take the TargetFragment
108 // as live, and throws IllegalStateException.
109 setTargetFragment(null, -1);
110
111 if (f != null && (f instanceof SettingsPreferenceFragment)) {
112 final SettingsPreferenceFragment spf = (SettingsPreferenceFragment)f;
113 final int resultCode = spf.getResultCode();
114 final Intent resultData = spf.getResultData();
115 onActivityResult(requestCode, resultCode, resultData);
116 }
117 }
118
Amith Yamasanid7993472010-08-18 13:59:28 -0700119 @Override
120 public void onActivityCreated(Bundle savedInstanceState) {
121 super.onActivityCreated(savedInstanceState);
Amith Yamasanib61cf512010-09-12 08:17:50 -0700122 if (mOnStateListener != null && !mReportedCreation) {
Amith Yamasanid7993472010-08-18 13:59:28 -0700123 mOnStateListener.onCreated(this);
Amith Yamasanib61cf512010-09-12 08:17:50 -0700124 // So that we don't report it on the way back to this fragment
125 mReportedCreation = true;
Amith Yamasanid7993472010-08-18 13:59:28 -0700126 }
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -0700127
128 setupButtonBar();
Amith Yamasanid7993472010-08-18 13:59:28 -0700129 }
130
Daisuke Miyakawab5647c52010-09-10 18:04:02 -0700131 public final void setResult(int resultCode) {
132 mResultCode = resultCode;
133 mResultData = null;
134 }
135
136 public final void setResult(int resultCode, Intent data) {
137 mResultCode = resultCode;
138 mResultData = data;
139 }
140
141 public final int getResultCode() {
142 return mResultCode;
143 }
144
145 public final Intent getResultData() {
146 return mResultData;
147 }
148
149 /*
150 * The name is intentionally made different from Activity#finish(), so that
151 * users won't misunderstand its meaning.
152 */
153 public final void finishFragment() {
154 getActivity().onBackPressed();
155 }
156
Amith Yamasanid7993472010-08-18 13:59:28 -0700157 @Override
158 public void onDestroy() {
159 super.onDestroy();
160 if (mOnStateListener != null) {
161 mOnStateListener.onDestroyed(this);
162 }
163 }
164
165 // Some helpers for functions used by the settings fragments when they were activities
166
167 /**
168 * Returns the ContentResolver from the owning Activity.
169 */
170 protected ContentResolver getContentResolver() {
171 return getActivity().getContentResolver();
172 }
173
174 /**
175 * Returns the specified system service from the owning Activity.
176 */
177 protected Object getSystemService(final String name) {
178 return getActivity().getSystemService(name);
179 }
180
181 /**
182 * Returns the Resources from the owning Activity.
183 */
184 protected Resources getResources() {
185 return getActivity().getResources();
186 }
187
188 /**
189 * Returns the PackageManager from the owning Activity.
190 */
191 protected PackageManager getPackageManager() {
192 return getActivity().getPackageManager();
193 }
194
195 // Dialog management
196
197 protected void showDialog(int dialogId) {
198 if (mDialogFragment != null) {
199 Log.e(TAG, "Old dialog fragment not null!");
200 }
201 mDialogFragment = new SettingsDialogFragment(this, dialogId);
Daisuke Miyakawa21c1abc2010-09-12 15:42:56 -0700202 mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId));
Amith Yamasanid7993472010-08-18 13:59:28 -0700203 }
204
Daisuke Miyakawa21c1abc2010-09-12 15:42:56 -0700205 @Override
Amith Yamasanid7993472010-08-18 13:59:28 -0700206 public Dialog onCreateDialog(int dialogId) {
207 return null;
208 }
209
210 protected void removeDialog(int dialogId) {
211 if (mDialogFragment != null && mDialogFragment.getDialogId() == dialogId
212 && mDialogFragment.isVisible()) {
213 mDialogFragment.dismiss();
214 }
215 mDialogFragment = null;
216 }
217
218 static class SettingsDialogFragment extends DialogFragment {
219 private int mDialogId;
220
Daisuke Miyakawa21c1abc2010-09-12 15:42:56 -0700221 private DialogCreatable mFragment;
Amith Yamasanid7993472010-08-18 13:59:28 -0700222
Daisuke Miyakawa21c1abc2010-09-12 15:42:56 -0700223 SettingsDialogFragment(DialogCreatable fragment, int dialogId) {
Amith Yamasanid7993472010-08-18 13:59:28 -0700224 mDialogId = dialogId;
225 mFragment = fragment;
226 }
227
228 @Override
229 public Dialog onCreateDialog(Bundle savedInstanceState) {
230 return mFragment.onCreateDialog(mDialogId);
231 }
232
233 public int getDialogId() {
234 return mDialogId;
235 }
236 }
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -0700237
238 protected boolean hasNextButton() {
239 return mNextButton != null;
240 }
241
242 protected Button getNextButton() {
243 return mNextButton;
244 }
245
Daisuke Miyakawa6ebf8612010-09-10 09:48:51 -0700246 public void finish() {
247 getActivity().onBackPressed();
248 }
249
Daisuke Miyakawab5647c52010-09-10 18:04:02 -0700250 public boolean startFragment(
251 Fragment caller, String fragmentClass, int requestCode, Bundle extras) {
252 if (mFragmentStarter != null) {
253 return mFragmentStarter.startFragment(caller, fragmentClass, requestCode, extras);
254 } else {
255 Log.w(TAG, "FragmentStarter is not set.");
256 return false;
257 }
258 }
259
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -0700260 /**
261 * Sets up Button Bar possibly required in the Fragment. Probably available only in
262 * phones.
263 *
264 * Previously {@link PreferenceActivity} had the capability as hidden functionality.
265 */
266 private void setupButtonBar() {
267 // Originally from PreferenceActivity, which has had button bar inside its layout.
268 final Activity activity = getActivity();
269 final Intent intent = activity.getIntent();
270 final View buttonBar = activity.findViewById(com.android.internal.R.id.button_bar);
271 if (!intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false) || buttonBar == null) {
272 return;
273 }
274
275 buttonBar.setVisibility(View.VISIBLE);
276 View tmpView = activity.findViewById(com.android.internal.R.id.back_button);
277 if (tmpView != null) {
278 // TODO: Assume this is pressed only in single pane, finishing current Activity.
279 try {
280 final Button backButton = (Button)tmpView;
281 backButton.setOnClickListener(new OnClickListener() {
282 public void onClick(View v) {
283 activity.setResult(Activity.RESULT_CANCELED);
284 activity.finish();
285 }
286 });
287 if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
288 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
289 if (TextUtils.isEmpty(buttonText)) {
290 backButton.setVisibility(View.GONE);
291 }
292 else {
293 backButton.setText(buttonText);
294 }
295 }
296 } catch (ClassCastException e) {
297 Log.w(TAG, "The view originally for back_button is used not as Button. " +
298 "Ignored.");
299 }
300 }
301
302 tmpView = activity.findViewById(com.android.internal.R.id.skip_button);
303 if (tmpView != null) {
304 try {
305 final Button skipButton = (Button)tmpView;
306 skipButton.setOnClickListener(new OnClickListener() {
307 public void onClick(View v) {
308 activity.setResult(Activity.RESULT_OK);
309 activity.finish();
310 }
311 });
312 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
313 skipButton.setVisibility(View.VISIBLE);
314 }
315 } catch (ClassCastException e) {
316 Log.w(TAG, "The view originally for skip_button is used not as Button. " +
317 "Ignored.");
318 }
319 }
320
321 tmpView = activity.findViewById(com.android.internal.R.id.next_button);
322 if (tmpView != null) {
323 try {
324 mNextButton = (Button)tmpView;
325 mNextButton.setOnClickListener(new OnClickListener() {
326 public void onClick(View v) {
327 activity.setResult(Activity.RESULT_OK);
328 activity.finish();
329 }
330 });
331 // set our various button parameters
332 if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
333 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
334 if (TextUtils.isEmpty(buttonText)) {
335 mNextButton.setVisibility(View.GONE);
336 }
337 else {
338 mNextButton.setText(buttonText);
339 }
340 }
341 } catch (ClassCastException e) {
342 Log.w(TAG, "The view originally for next_button is used not as Button. " +
343 "Ignored.");
344 mNextButton = null;
345 }
346 }
347 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700348}