1 /* 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 17 package com.android.settings; 18 19 import android.app.Dialog; 20 import android.app.DialogFragment; 21 import android.app.Fragment; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.Intent; 26 import android.content.pm.PackageManager; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.preference.Preference; 30 import android.preference.PreferenceActivity; 31 import android.preference.PreferenceFragment; 32 import android.text.TextUtils; 33 import android.util.Log; 34 import android.view.Menu; 35 import android.view.MenuInflater; 36 import android.view.MenuItem; 37 import android.widget.Button; 38 39 /** 40 * Base class for Settings fragments, with some helper functions and dialog management. 41 */ 42 public class SettingsPreferenceFragment extends PreferenceFragment implements DialogCreatable { 43 44 private static final String TAG = "SettingsPreferenceFragment"; 45 46 private static final int MENU_HELP = Menu.FIRST + 100; 47 48 private SettingsDialogFragment mDialogFragment; 49 50 private String mHelpUrl; 51 52 // Cache the content resolver for async callbacks 53 private ContentResolver mContentResolver; 54 55 @Override 56 public void onCreate(Bundle icicle) { 57 super.onCreate(icicle); 58 59 // Prepare help url and enable menu if necessary 60 int helpResource = getHelpResource(); 61 if (helpResource != 0) { 62 mHelpUrl = getResources().getString(helpResource); 63 } 64 } 65 66 @Override 67 public void onActivityCreated(Bundle savedInstanceState) { 68 super.onActivityCreated(savedInstanceState); 69 if (!TextUtils.isEmpty(mHelpUrl)) { 70 setHasOptionsMenu(true); 71 } 72 } 73 74 protected void removePreference(String key) { 75 Preference pref = findPreference(key); 76 if (pref != null) { 77 getPreferenceScreen().removePreference(pref); 78 } 79 } 80 81 /** 82 * Override this if you want to show a help item in the menu, by returning the resource id. 83 * @return the resource id for the help url 84 */ 85 protected int getHelpResource() { 86 return 0; 87 } 88 89 @Override 90 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 91 if (mHelpUrl != null && getActivity() != null) { 92 MenuItem helpItem = menu.add(0, MENU_HELP, 0, R.string.help_label); 93 HelpUtils.prepareHelpMenuItem(getActivity(), helpItem, mHelpUrl); 94 } 95 } 96 97 /* 98 * The name is intentionally made different from Activity#finish(), so that 99 * users won't misunderstand its meaning. 100 */ 101 public final void finishFragment() { 102 getActivity().onBackPressed(); 103 } 104 105 // Some helpers for functions used by the settings fragments when they were activities 106 107 /** 108 * Returns the ContentResolver from the owning Activity. 109 */ 110 protected ContentResolver getContentResolver() { 111 Context context = getActivity(); 112 if (context != null) { 113 mContentResolver = context.getContentResolver(); 114 } 115 return mContentResolver; 116 } 117 118 /** 119 * Returns the specified system service from the owning Activity. 120 */ 121 protected Object getSystemService(final String name) { 122 return getActivity().getSystemService(name); 123 } 124 125 /** 126 * Returns the PackageManager from the owning Activity. 127 */ 128 protected PackageManager getPackageManager() { 129 return getActivity().getPackageManager(); 130 } 131 132 @Override 133 public void onDetach() { 134 if (isRemoving()) { 135 if (mDialogFragment != null) { 136 mDialogFragment.dismiss(); 137 mDialogFragment = null; 138 } 139 } 140 super.onDetach(); 141 } 142 143 // Dialog management 144 145 protected void showDialog(int dialogId) { 146 if (mDialogFragment != null) { 147 Log.e(TAG, "Old dialog fragment not null!"); 148 } 149 mDialogFragment = new SettingsDialogFragment(this, dialogId); 150 mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId)); 151 } 152 153 public Dialog onCreateDialog(int dialogId) { 154 return null; 155 } 156 157 protected void removeDialog(int dialogId) { 158 // mDialogFragment may not be visible yet in parent fragment's onResume(). 159 // To be able to dismiss dialog at that time, don't check 160 // mDialogFragment.isVisible(). 161 if (mDialogFragment != null && mDialogFragment.getDialogId() == dialogId) { 162 mDialogFragment.dismiss(); 163 } 164 mDialogFragment = null; 165 } 166 167 /** 168 * Sets the OnCancelListener of the dialog shown. This method can only be 169 * called after showDialog(int) and before removeDialog(int). The method 170 * does nothing otherwise. 171 */ 172 protected void setOnCancelListener(DialogInterface.OnCancelListener listener) { 173 if (mDialogFragment != null) { 174 mDialogFragment.mOnCancelListener = listener; 175 } 176 } 177 178 /** 179 * Sets the OnDismissListener of the dialog shown. This method can only be 180 * called after showDialog(int) and before removeDialog(int). The method 181 * does nothing otherwise. 182 */ 183 protected void setOnDismissListener(DialogInterface.OnDismissListener listener) { 184 if (mDialogFragment != null) { 185 mDialogFragment.mOnDismissListener = listener; 186 } 187 } 188 189 public void onDialogShowing() { 190 // override in subclass to attach a dismiss listener, for instance 191 } 192 193 public static class SettingsDialogFragment extends DialogFragment { 194 private static final String KEY_DIALOG_ID = "key_dialog_id"; 195 private static final String KEY_PARENT_FRAGMENT_ID = "key_parent_fragment_id"; 196 197 private int mDialogId; 198 199 private Fragment mParentFragment; 200 201 private DialogInterface.OnCancelListener mOnCancelListener; 202 private DialogInterface.OnDismissListener mOnDismissListener; 203 204 public SettingsDialogFragment() { 205 /* do nothing */ 206 } 207 208 public SettingsDialogFragment(DialogCreatable fragment, int dialogId) { 209 mDialogId = dialogId; 210 if (!(fragment instanceof Fragment)) { 211 throw new IllegalArgumentException("fragment argument must be an instance of " 212 + Fragment.class.getName()); 213 } 214 mParentFragment = (Fragment) fragment; 215 } 216 217 @Override 218 public void onSaveInstanceState(Bundle outState) { 219 super.onSaveInstanceState(outState); 220 if (mParentFragment != null) { 221 outState.putInt(KEY_DIALOG_ID, mDialogId); 222 outState.putInt(KEY_PARENT_FRAGMENT_ID, mParentFragment.getId()); 223 } 224 } 225 226 @Override 227 public void onStart() { 228 super.onStart(); 229 230 if (mParentFragment != null && mParentFragment instanceof SettingsPreferenceFragment) { 231 ((SettingsPreferenceFragment) mParentFragment).onDialogShowing(); 232 } 233 } 234 235 @Override 236 public Dialog onCreateDialog(Bundle savedInstanceState) { 237 if (savedInstanceState != null) { 238 mDialogId = savedInstanceState.getInt(KEY_DIALOG_ID, 0); 239 int mParentFragmentId = savedInstanceState.getInt(KEY_PARENT_FRAGMENT_ID, -1); 240 if (mParentFragmentId > -1) { 241 mParentFragment = getFragmentManager().findFragmentById(mParentFragmentId); 242 if (!(mParentFragment instanceof DialogCreatable)) { 243 throw new IllegalArgumentException( 244 (mParentFragment != null 245 ? mParentFragment.getClass().getName() 246 : mParentFragmentId) 247 + " must implement " 248 + DialogCreatable.class.getName()); 249 } 250 } 251 // This dialog fragment could be created from non-SettingsPreferenceFragment 252 if (mParentFragment instanceof SettingsPreferenceFragment) { 253 // restore mDialogFragment in mParentFragment 254 ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = this; 255 } 256 } 257 return ((DialogCreatable) mParentFragment).onCreateDialog(mDialogId); 258 } 259 260 @Override 261 public void onCancel(DialogInterface dialog) { 262 super.onCancel(dialog); 263 if (mOnCancelListener != null) { 264 mOnCancelListener.onCancel(dialog); 265 } 266 } 267 268 @Override 269 public void onDismiss(DialogInterface dialog) { 270 super.onDismiss(dialog); 271 if (mOnDismissListener != null) { 272 mOnDismissListener.onDismiss(dialog); 273 } 274 } 275 276 public int getDialogId() { 277 return mDialogId; 278 } 279 280 @Override 281 public void onDetach() { 282 super.onDetach(); 283 284 // This dialog fragment could be created from non-SettingsPreferenceFragment 285 if (mParentFragment instanceof SettingsPreferenceFragment) { 286 // in case the dialog is not explicitly removed by removeDialog() 287 if (((SettingsPreferenceFragment) mParentFragment).mDialogFragment == this) { 288 ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = null; 289 } 290 } 291 } 292 } 293 294 protected boolean hasNextButton() { 295 return ((ButtonBarHandler)getActivity()).hasNextButton(); 296 } 297 298 protected Button getNextButton() { 299 return ((ButtonBarHandler)getActivity()).getNextButton(); 300 } 301 302 public void finish() { 303 getActivity().onBackPressed(); 304 } 305 306 public boolean startFragment( 307 Fragment caller, String fragmentClass, int requestCode, Bundle extras) { 308 if (getActivity() instanceof PreferenceActivity) { 309 PreferenceActivity preferenceActivity = (PreferenceActivity)getActivity(); 310 preferenceActivity.startPreferencePanel(fragmentClass, extras, 311 R.string.lock_settings_picker_title, null, caller, requestCode); 312 return true; 313 } else { 314 Log.w(TAG, "Parent isn't PreferenceActivity, thus there's no way to launch the " 315 + "given Fragment (name: " + fragmentClass + ", requestCode: " + requestCode 316 + ")"); 317 return false; 318 } 319 } 320 321 } 322