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