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.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