Home | History | Annotate | Download | only in settings
      1 /*
      2  * Copyright (C) 2008 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 com.android.internal.util.ArrayUtils;
     20 import com.android.settings.accounts.AccountSyncSettings;
     21 import com.android.settings.accounts.AuthenticatorHelper;
     22 import com.android.settings.accounts.ManageAccountsSettings;
     23 import com.android.settings.applications.ManageApplications;
     24 import com.android.settings.bluetooth.BluetoothEnabler;
     25 import com.android.settings.deviceinfo.Memory;
     26 import com.android.settings.fuelgauge.PowerUsageSummary;
     27 import com.android.settings.wifi.WifiEnabler;
     28 
     29 import android.accounts.Account;
     30 import android.accounts.AccountManager;
     31 import android.accounts.OnAccountsUpdateListener;
     32 import android.content.ComponentName;
     33 import android.content.Context;
     34 import android.content.Intent;
     35 import android.content.pm.ActivityInfo;
     36 import android.content.pm.PackageManager;
     37 import android.content.pm.PackageManager.NameNotFoundException;
     38 import android.graphics.drawable.Drawable;
     39 import android.os.Bundle;
     40 import android.os.INetworkManagementService;
     41 import android.os.RemoteException;
     42 import android.os.ServiceManager;
     43 import android.os.UserId;
     44 import android.preference.Preference;
     45 import android.preference.PreferenceActivity;
     46 import android.preference.PreferenceActivity.Header;
     47 import android.preference.PreferenceFragment;
     48 import android.text.TextUtils;
     49 import android.util.Log;
     50 import android.view.LayoutInflater;
     51 import android.view.View;
     52 import android.view.View.OnClickListener;
     53 import android.view.ViewGroup;
     54 import android.widget.ArrayAdapter;
     55 import android.widget.BaseAdapter;
     56 import android.widget.Button;
     57 import android.widget.ImageView;
     58 import android.widget.ListAdapter;
     59 import android.widget.Switch;
     60 import android.widget.TextView;
     61 
     62 import java.util.ArrayList;
     63 import java.util.Collections;
     64 import java.util.Comparator;
     65 import java.util.HashMap;
     66 import java.util.List;
     67 
     68 /**
     69  * Top-level settings activity to handle single pane and double pane UI layout.
     70  */
     71 public class Settings extends PreferenceActivity
     72         implements ButtonBarHandler, OnAccountsUpdateListener {
     73 
     74     private static final String LOG_TAG = "Settings";
     75 
     76     private static final String META_DATA_KEY_HEADER_ID =
     77         "com.android.settings.TOP_LEVEL_HEADER_ID";
     78     private static final String META_DATA_KEY_FRAGMENT_CLASS =
     79         "com.android.settings.FRAGMENT_CLASS";
     80     private static final String META_DATA_KEY_PARENT_TITLE =
     81         "com.android.settings.PARENT_FRAGMENT_TITLE";
     82     private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
     83         "com.android.settings.PARENT_FRAGMENT_CLASS";
     84 
     85     private static final String EXTRA_CLEAR_UI_OPTIONS = "settings:remove_ui_options";
     86 
     87     private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
     88     private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
     89 
     90     private String mFragmentClass;
     91     private int mTopLevelHeaderId;
     92     private Header mFirstHeader;
     93     private Header mCurrentHeader;
     94     private Header mParentHeader;
     95     private boolean mInLocalHeaderSwitch;
     96 
     97     // Show only these settings for restricted users
     98     private int[] SETTINGS_FOR_RESTRICTED = {
     99             R.id.wifi_settings,
    100             R.id.bluetooth_settings,
    101             R.id.sound_settings,
    102             R.id.display_settings,
    103             R.id.security_settings,
    104             R.id.account_settings,
    105             R.id.about_settings
    106     };
    107 
    108     private boolean mEnableUserManagement = false;
    109 
    110     // TODO: Update Call Settings based on airplane mode state.
    111 
    112     protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
    113 
    114     private AuthenticatorHelper mAuthenticatorHelper;
    115     private Header mLastHeader;
    116     private boolean mListeningToAccountUpdates;
    117 
    118     @Override
    119     protected void onCreate(Bundle savedInstanceState) {
    120         if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {
    121             getWindow().setUiOptions(0);
    122         }
    123 
    124         if (android.provider.Settings.Secure.getInt(getContentResolver(), "multiuser_enabled", -1)
    125                 > 0) {
    126             mEnableUserManagement = true;
    127         }
    128 
    129         mAuthenticatorHelper = new AuthenticatorHelper();
    130         mAuthenticatorHelper.updateAuthDescriptions(this);
    131         mAuthenticatorHelper.onAccountsUpdated(this, null);
    132 
    133         getMetaData();
    134         mInLocalHeaderSwitch = true;
    135         super.onCreate(savedInstanceState);
    136         mInLocalHeaderSwitch = false;
    137 
    138         if (!onIsHidingHeaders() && onIsMultiPane()) {
    139             highlightHeader(mTopLevelHeaderId);
    140             // Force the title so that it doesn't get overridden by a direct launch of
    141             // a specific settings screen.
    142             setTitle(R.string.settings_label);
    143         }
    144 
    145         // Retrieve any saved state
    146         if (savedInstanceState != null) {
    147             mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
    148             mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
    149         }
    150 
    151         // If the current header was saved, switch to it
    152         if (savedInstanceState != null && mCurrentHeader != null) {
    153             //switchToHeaderLocal(mCurrentHeader);
    154             showBreadCrumbs(mCurrentHeader.title, null);
    155         }
    156 
    157         if (mParentHeader != null) {
    158             setParentTitle(mParentHeader.title, null, new OnClickListener() {
    159                 public void onClick(View v) {
    160                     switchToParent(mParentHeader.fragment);
    161                 }
    162             });
    163         }
    164 
    165         // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
    166         if (onIsMultiPane()) {
    167             getActionBar().setDisplayHomeAsUpEnabled(false);
    168             getActionBar().setHomeButtonEnabled(false);
    169         }
    170     }
    171 
    172     @Override
    173     protected void onSaveInstanceState(Bundle outState) {
    174         super.onSaveInstanceState(outState);
    175 
    176         // Save the current fragment, if it is the same as originally launched
    177         if (mCurrentHeader != null) {
    178             outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
    179         }
    180         if (mParentHeader != null) {
    181             outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
    182         }
    183     }
    184 
    185     @Override
    186     public void onResume() {
    187         super.onResume();
    188 
    189         ListAdapter listAdapter = getListAdapter();
    190         if (listAdapter instanceof HeaderAdapter) {
    191             ((HeaderAdapter) listAdapter).resume();
    192         }
    193         invalidateHeaders();
    194     }
    195 
    196     @Override
    197     public void onPause() {
    198         super.onPause();
    199 
    200         ListAdapter listAdapter = getListAdapter();
    201         if (listAdapter instanceof HeaderAdapter) {
    202             ((HeaderAdapter) listAdapter).pause();
    203         }
    204     }
    205 
    206     @Override
    207     public void onDestroy() {
    208         super.onDestroy();
    209         if (mListeningToAccountUpdates) {
    210             AccountManager.get(this).removeOnAccountsUpdatedListener(this);
    211         }
    212     }
    213 
    214     private void switchToHeaderLocal(Header header) {
    215         mInLocalHeaderSwitch = true;
    216         switchToHeader(header);
    217         mInLocalHeaderSwitch = false;
    218     }
    219 
    220     @Override
    221     public void switchToHeader(Header header) {
    222         if (!mInLocalHeaderSwitch) {
    223             mCurrentHeader = null;
    224             mParentHeader = null;
    225         }
    226         super.switchToHeader(header);
    227     }
    228 
    229     /**
    230      * Switch to parent fragment and store the grand parent's info
    231      * @param className name of the activity wrapper for the parent fragment.
    232      */
    233     private void switchToParent(String className) {
    234         final ComponentName cn = new ComponentName(this, className);
    235         try {
    236             final PackageManager pm = getPackageManager();
    237             final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
    238 
    239             if (parentInfo != null && parentInfo.metaData != null) {
    240                 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
    241                 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
    242                 Header parentHeader = new Header();
    243                 parentHeader.fragment = fragmentClass;
    244                 parentHeader.title = fragmentTitle;
    245                 mCurrentHeader = parentHeader;
    246 
    247                 switchToHeaderLocal(parentHeader);
    248                 highlightHeader(mTopLevelHeaderId);
    249 
    250                 mParentHeader = new Header();
    251                 mParentHeader.fragment
    252                         = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
    253                 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
    254             }
    255         } catch (NameNotFoundException nnfe) {
    256             Log.w(LOG_TAG, "Could not find parent activity : " + className);
    257         }
    258     }
    259 
    260     @Override
    261     public void onNewIntent(Intent intent) {
    262         super.onNewIntent(intent);
    263 
    264         // If it is not launched from history, then reset to top-level
    265         if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0
    266                 && mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
    267             switchToHeaderLocal(mFirstHeader);
    268         }
    269     }
    270 
    271     private void highlightHeader(int id) {
    272         if (id != 0) {
    273             Integer index = mHeaderIndexMap.get(id);
    274             if (index != null) {
    275                 getListView().setItemChecked(index, true);
    276                 getListView().smoothScrollToPosition(index);
    277             }
    278         }
    279     }
    280 
    281     @Override
    282     public Intent getIntent() {
    283         Intent superIntent = super.getIntent();
    284         String startingFragment = getStartingFragmentClass(superIntent);
    285         // This is called from super.onCreate, isMultiPane() is not yet reliable
    286         // Do not use onIsHidingHeaders either, which relies itself on this method
    287         if (startingFragment != null && !onIsMultiPane()) {
    288             Intent modIntent = new Intent(superIntent);
    289             modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
    290             Bundle args = superIntent.getExtras();
    291             if (args != null) {
    292                 args = new Bundle(args);
    293             } else {
    294                 args = new Bundle();
    295             }
    296             args.putParcelable("intent", superIntent);
    297             modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
    298             return modIntent;
    299         }
    300         return superIntent;
    301     }
    302 
    303     /**
    304      * Checks if the component name in the intent is different from the Settings class and
    305      * returns the class name to load as a fragment.
    306      */
    307     protected String getStartingFragmentClass(Intent intent) {
    308         if (mFragmentClass != null) return mFragmentClass;
    309 
    310         String intentClass = intent.getComponent().getClassName();
    311         if (intentClass.equals(getClass().getName())) return null;
    312 
    313         if ("com.android.settings.ManageApplications".equals(intentClass)
    314                 || "com.android.settings.RunningServices".equals(intentClass)
    315                 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
    316             // Old names of manage apps.
    317             intentClass = com.android.settings.applications.ManageApplications.class.getName();
    318         }
    319 
    320         return intentClass;
    321     }
    322 
    323     /**
    324      * Override initial header when an activity-alias is causing Settings to be launched
    325      * for a specific fragment encoded in the android:name parameter.
    326      */
    327     @Override
    328     public Header onGetInitialHeader() {
    329         String fragmentClass = getStartingFragmentClass(super.getIntent());
    330         if (fragmentClass != null) {
    331             Header header = new Header();
    332             header.fragment = fragmentClass;
    333             header.title = getTitle();
    334             header.fragmentArguments = getIntent().getExtras();
    335             mCurrentHeader = header;
    336             return header;
    337         }
    338 
    339         return mFirstHeader;
    340     }
    341 
    342     @Override
    343     public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
    344             int titleRes, int shortTitleRes) {
    345         Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
    346                 titleRes, shortTitleRes);
    347 
    348         // some fragments want to avoid split actionbar
    349         if (DataUsageSummary.class.getName().equals(fragmentName) ||
    350                 PowerUsageSummary.class.getName().equals(fragmentName) ||
    351                 AccountSyncSettings.class.getName().equals(fragmentName) ||
    352                 UserDictionarySettings.class.getName().equals(fragmentName) ||
    353                 Memory.class.getName().equals(fragmentName) ||
    354                 ManageApplications.class.getName().equals(fragmentName) ||
    355                 WirelessSettings.class.getName().equals(fragmentName) ||
    356                 SoundSettings.class.getName().equals(fragmentName) ||
    357                 PrivacySettings.class.getName().equals(fragmentName) ||
    358                 ManageAccountsSettings.class.getName().equals(fragmentName)) {
    359             intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true);
    360         }
    361 
    362         intent.setClass(this, SubSettings.class);
    363         return intent;
    364     }
    365 
    366     /**
    367      * Populate the activity with the top-level headers.
    368      */
    369     @Override
    370     public void onBuildHeaders(List<Header> headers) {
    371         loadHeadersFromResource(R.xml.settings_headers, headers);
    372 
    373         updateHeaderList(headers);
    374     }
    375 
    376     private void updateHeaderList(List<Header> target) {
    377         int i = 0;
    378         while (i < target.size()) {
    379             Header header = target.get(i);
    380             // Ids are integers, so downcasting
    381             int id = (int) header.id;
    382             if (id == R.id.dock_settings) {
    383                 if (!needsDockSettings())
    384                     target.remove(header);
    385             } else if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
    386                 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
    387             } else if (id == R.id.wifi_settings) {
    388                 // Remove WiFi Settings if WiFi service is not available.
    389                 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
    390                     target.remove(header);
    391                 }
    392             } else if (id == R.id.bluetooth_settings) {
    393                 // Remove Bluetooth Settings if Bluetooth service is not available.
    394                 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
    395                     target.remove(header);
    396                 }
    397             } else if (id == R.id.data_usage_settings) {
    398                 // Remove data usage when kernel module not enabled
    399                 final INetworkManagementService netManager = INetworkManagementService.Stub
    400                         .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
    401                 try {
    402                     if (!netManager.isBandwidthControlEnabled()) {
    403                         target.remove(header);
    404                     }
    405                 } catch (RemoteException e) {
    406                     // ignored
    407                 }
    408             } else if (id == R.id.account_settings) {
    409                 int headerIndex = i + 1;
    410                 i = insertAccountsHeaders(target, headerIndex);
    411             } else if (id == R.id.user_settings) {
    412                 if (!mEnableUserManagement
    413                         || !UserId.MU_ENABLED || UserId.myUserId() != 0
    414                         || !getResources().getBoolean(R.bool.enable_user_management)
    415                         || Utils.isMonkeyRunning()) {
    416                     target.remove(header);
    417                 }
    418             }
    419             if (UserId.MU_ENABLED && UserId.myUserId() != 0
    420                     && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
    421                 target.remove(header);
    422             }
    423 
    424             // Increment if the current one wasn't removed by the Utils code.
    425             if (target.get(i) == header) {
    426                 // Hold on to the first header, when we need to reset to the top-level
    427                 if (mFirstHeader == null &&
    428                         HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
    429                     mFirstHeader = header;
    430                 }
    431                 mHeaderIndexMap.put(id, i);
    432                 i++;
    433             }
    434         }
    435     }
    436 
    437     private int insertAccountsHeaders(List<Header> target, int headerIndex) {
    438         String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
    439         List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
    440         for (String accountType : accountTypes) {
    441             CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
    442             if (label == null) {
    443                 continue;
    444             }
    445 
    446             Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
    447             boolean skipToAccount = accounts.length == 1
    448                     && !mAuthenticatorHelper.hasAccountPreferences(accountType);
    449             Header accHeader = new Header();
    450             accHeader.title = label;
    451             if (accHeader.extras == null) {
    452                 accHeader.extras = new Bundle();
    453             }
    454             if (skipToAccount) {
    455                 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
    456                 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
    457                 accHeader.fragment = AccountSyncSettings.class.getName();
    458                 accHeader.fragmentArguments = new Bundle();
    459                 // Need this for the icon
    460                 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
    461                 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
    462                 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
    463                         accounts[0]);
    464             } else {
    465                 accHeader.breadCrumbTitle = label;
    466                 accHeader.breadCrumbShortTitle = label;
    467                 accHeader.fragment = ManageAccountsSettings.class.getName();
    468                 accHeader.fragmentArguments = new Bundle();
    469                 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
    470                 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
    471                         accountType);
    472                 if (!isMultiPane()) {
    473                     accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
    474                             label.toString());
    475                 }
    476             }
    477             accountHeaders.add(accHeader);
    478         }
    479 
    480         // Sort by label
    481         Collections.sort(accountHeaders, new Comparator<Header>() {
    482             @Override
    483             public int compare(Header h1, Header h2) {
    484                 return h1.title.toString().compareTo(h2.title.toString());
    485             }
    486         });
    487 
    488         for (Header header : accountHeaders) {
    489             target.add(headerIndex++, header);
    490         }
    491         if (!mListeningToAccountUpdates) {
    492             AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
    493             mListeningToAccountUpdates = true;
    494         }
    495         return headerIndex;
    496     }
    497 
    498     private boolean needsDockSettings() {
    499         return getResources().getBoolean(R.bool.has_dock_settings);
    500     }
    501 
    502     private void getMetaData() {
    503         try {
    504             ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
    505                     PackageManager.GET_META_DATA);
    506             if (ai == null || ai.metaData == null) return;
    507             mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
    508             mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
    509 
    510             // Check if it has a parent specified and create a Header object
    511             final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
    512             String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
    513             if (parentFragmentClass != null) {
    514                 mParentHeader = new Header();
    515                 mParentHeader.fragment = parentFragmentClass;
    516                 if (parentHeaderTitleRes != 0) {
    517                     mParentHeader.title = getResources().getString(parentHeaderTitleRes);
    518                 }
    519             }
    520         } catch (NameNotFoundException nnfe) {
    521             // No recovery
    522         }
    523     }
    524 
    525     @Override
    526     public boolean hasNextButton() {
    527         return super.hasNextButton();
    528     }
    529 
    530     @Override
    531     public Button getNextButton() {
    532         return super.getNextButton();
    533     }
    534 
    535     private static class HeaderAdapter extends ArrayAdapter<Header> {
    536         static final int HEADER_TYPE_CATEGORY = 0;
    537         static final int HEADER_TYPE_NORMAL = 1;
    538         static final int HEADER_TYPE_SWITCH = 2;
    539         private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;
    540 
    541         private final WifiEnabler mWifiEnabler;
    542         private final BluetoothEnabler mBluetoothEnabler;
    543         private AuthenticatorHelper mAuthHelper;
    544 
    545         private static class HeaderViewHolder {
    546             ImageView icon;
    547             TextView title;
    548             TextView summary;
    549             Switch switch_;
    550         }
    551 
    552         private LayoutInflater mInflater;
    553 
    554         static int getHeaderType(Header header) {
    555             if (header.fragment == null && header.intent == null) {
    556                 return HEADER_TYPE_CATEGORY;
    557             } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
    558                 return HEADER_TYPE_SWITCH;
    559             } else {
    560                 return HEADER_TYPE_NORMAL;
    561             }
    562         }
    563 
    564         @Override
    565         public int getItemViewType(int position) {
    566             Header header = getItem(position);
    567             return getHeaderType(header);
    568         }
    569 
    570         @Override
    571         public boolean areAllItemsEnabled() {
    572             return false; // because of categories
    573         }
    574 
    575         @Override
    576         public boolean isEnabled(int position) {
    577             return getItemViewType(position) != HEADER_TYPE_CATEGORY;
    578         }
    579 
    580         @Override
    581         public int getViewTypeCount() {
    582             return HEADER_TYPE_COUNT;
    583         }
    584 
    585         @Override
    586         public boolean hasStableIds() {
    587             return true;
    588         }
    589 
    590         public HeaderAdapter(Context context, List<Header> objects,
    591                 AuthenticatorHelper authenticatorHelper) {
    592             super(context, 0, objects);
    593 
    594             mAuthHelper = authenticatorHelper;
    595             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    596 
    597             // Temp Switches provided as placeholder until the adapter replaces these with actual
    598             // Switches inflated from their layouts. Must be done before adapter is set in super
    599             mWifiEnabler = new WifiEnabler(context, new Switch(context));
    600             mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
    601         }
    602 
    603         @Override
    604         public View getView(int position, View convertView, ViewGroup parent) {
    605             HeaderViewHolder holder;
    606             Header header = getItem(position);
    607             int headerType = getHeaderType(header);
    608             View view = null;
    609 
    610             if (convertView == null) {
    611                 holder = new HeaderViewHolder();
    612                 switch (headerType) {
    613                     case HEADER_TYPE_CATEGORY:
    614                         view = new TextView(getContext(), null,
    615                                 android.R.attr.listSeparatorTextViewStyle);
    616                         holder.title = (TextView) view;
    617                         break;
    618 
    619                     case HEADER_TYPE_SWITCH:
    620                         view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
    621                                 false);
    622                         holder.icon = (ImageView) view.findViewById(R.id.icon);
    623                         holder.title = (TextView)
    624                                 view.findViewById(com.android.internal.R.id.title);
    625                         holder.summary = (TextView)
    626                                 view.findViewById(com.android.internal.R.id.summary);
    627                         holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
    628                         break;
    629 
    630                     case HEADER_TYPE_NORMAL:
    631                         view = mInflater.inflate(
    632                                 R.layout.preference_header_item, parent,
    633                                 false);
    634                         holder.icon = (ImageView) view.findViewById(R.id.icon);
    635                         holder.title = (TextView)
    636                                 view.findViewById(com.android.internal.R.id.title);
    637                         holder.summary = (TextView)
    638                                 view.findViewById(com.android.internal.R.id.summary);
    639                         break;
    640                 }
    641                 view.setTag(holder);
    642             } else {
    643                 view = convertView;
    644                 holder = (HeaderViewHolder) view.getTag();
    645             }
    646 
    647             // All view fields must be updated every time, because the view may be recycled
    648             switch (headerType) {
    649                 case HEADER_TYPE_CATEGORY:
    650                     holder.title.setText(header.getTitle(getContext().getResources()));
    651                     break;
    652 
    653                 case HEADER_TYPE_SWITCH:
    654                     // Would need a different treatment if the main menu had more switches
    655                     if (header.id == R.id.wifi_settings) {
    656                         mWifiEnabler.setSwitch(holder.switch_);
    657                     } else {
    658                         mBluetoothEnabler.setSwitch(holder.switch_);
    659                     }
    660                     // No break, fall through on purpose to update common fields
    661 
    662                     //$FALL-THROUGH$
    663                 case HEADER_TYPE_NORMAL:
    664                     if (header.extras != null
    665                             && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
    666                         String accType = header.extras.getString(
    667                                 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
    668                         ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
    669                         lp.width = getContext().getResources().getDimensionPixelSize(
    670                                 R.dimen.header_icon_width);
    671                         lp.height = lp.width;
    672                         holder.icon.setLayoutParams(lp);
    673                         Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
    674                         holder.icon.setImageDrawable(icon);
    675                     } else {
    676                         holder.icon.setImageResource(header.iconRes);
    677                     }
    678                     holder.title.setText(header.getTitle(getContext().getResources()));
    679                     CharSequence summary = header.getSummary(getContext().getResources());
    680                     if (!TextUtils.isEmpty(summary)) {
    681                         holder.summary.setVisibility(View.VISIBLE);
    682                         holder.summary.setText(summary);
    683                     } else {
    684                         holder.summary.setVisibility(View.GONE);
    685                     }
    686                     break;
    687             }
    688 
    689             return view;
    690         }
    691 
    692         public void resume() {
    693             mWifiEnabler.resume();
    694             mBluetoothEnabler.resume();
    695         }
    696 
    697         public void pause() {
    698             mWifiEnabler.pause();
    699             mBluetoothEnabler.pause();
    700         }
    701     }
    702 
    703     @Override
    704     public void onHeaderClick(Header header, int position) {
    705         boolean revert = false;
    706         if (header.id == R.id.account_add) {
    707             revert = true;
    708         }
    709 
    710         super.onHeaderClick(header, position);
    711 
    712         if (revert && mLastHeader != null) {
    713             highlightHeader((int) mLastHeader.id);
    714         } else {
    715             mLastHeader = header;
    716         }
    717     }
    718 
    719     @Override
    720     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
    721         // Override the fragment title for Wallpaper settings
    722         int titleRes = pref.getTitleRes();
    723         if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
    724             titleRes = R.string.wallpaper_settings_fragment_title;
    725         }
    726         startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
    727                 null, 0);
    728         return true;
    729     }
    730 
    731     public boolean shouldUpRecreateTask(Intent targetIntent) {
    732         return super.shouldUpRecreateTask(new Intent(this, Settings.class));
    733     }
    734 
    735     @Override
    736     public void setListAdapter(ListAdapter adapter) {
    737         if (adapter == null) {
    738             super.setListAdapter(null);
    739         } else {
    740             super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper));
    741         }
    742     }
    743 
    744     @Override
    745     public void onAccountsUpdated(Account[] accounts) {
    746         mAuthenticatorHelper.onAccountsUpdated(this, accounts);
    747         invalidateHeaders();
    748     }
    749 
    750     /*
    751      * Settings subclasses for launching independently.
    752      */
    753     public static class BluetoothSettingsActivity extends Settings { /* empty */ }
    754     public static class WirelessSettingsActivity extends Settings { /* empty */ }
    755     public static class TetherSettingsActivity extends Settings { /* empty */ }
    756     public static class VpnSettingsActivity extends Settings { /* empty */ }
    757     public static class DateTimeSettingsActivity extends Settings { /* empty */ }
    758     public static class StorageSettingsActivity extends Settings { /* empty */ }
    759     public static class WifiSettingsActivity extends Settings { /* empty */ }
    760     public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
    761     public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
    762     public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
    763     public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
    764     public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
    765     public static class LocalePickerActivity extends Settings { /* empty */ }
    766     public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
    767     public static class SoundSettingsActivity extends Settings { /* empty */ }
    768     public static class DisplaySettingsActivity extends Settings { /* empty */ }
    769     public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
    770     public static class ApplicationSettingsActivity extends Settings { /* empty */ }
    771     public static class ManageApplicationsActivity extends Settings { /* empty */ }
    772     public static class StorageUseActivity extends Settings { /* empty */ }
    773     public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
    774     public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
    775     public static class SecuritySettingsActivity extends Settings { /* empty */ }
    776     public static class LocationSettingsActivity extends Settings { /* empty */ }
    777     public static class PrivacySettingsActivity extends Settings { /* empty */ }
    778     public static class DockSettingsActivity extends Settings { /* empty */ }
    779     public static class RunningServicesActivity extends Settings { /* empty */ }
    780     public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
    781     public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
    782     public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
    783     public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
    784     public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
    785     public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
    786     public static class DataUsageSummaryActivity extends Settings { /* empty */ }
    787     public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
    788     public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
    789     public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
    790 }
    791