Home | History | Annotate | Download | only in settings
      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