• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
onCreate(Bundle savedInstanceState)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
onSaveInstanceState(Bundle outState)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
onResume()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
onPause()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
onDestroy()207     public void onDestroy() {
208         super.onDestroy();
209         if (mListeningToAccountUpdates) {
210             AccountManager.get(this).removeOnAccountsUpdatedListener(this);
211         }
212     }
213 
switchToHeaderLocal(Header header)214     private void switchToHeaderLocal(Header header) {
215         mInLocalHeaderSwitch = true;
216         switchToHeader(header);
217         mInLocalHeaderSwitch = false;
218     }
219 
220     @Override
switchToHeader(Header header)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      */
switchToParent(String className)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
onNewIntent(Intent intent)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 
highlightHeader(int id)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
getIntent()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      */
getStartingFragmentClass(Intent intent)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
onGetInitialHeader()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
onBuildStartFragmentIntent(String fragmentName, Bundle args, int titleRes, int shortTitleRes)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
onBuildHeaders(List<Header> headers)370     public void onBuildHeaders(List<Header> headers) {
371         loadHeadersFromResource(R.xml.settings_headers, headers);
372 
373         updateHeaderList(headers);
374     }
375 
updateHeaderList(List<Header> target)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 
insertAccountsHeaders(List<Header> target, int headerIndex)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 
needsDockSettings()498     private boolean needsDockSettings() {
499         return getResources().getBoolean(R.bool.has_dock_settings);
500     }
501 
getMetaData()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
hasNextButton()526     public boolean hasNextButton() {
527         return super.hasNextButton();
528     }
529 
530     @Override
getNextButton()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 
getHeaderType(Header header)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
getItemViewType(int position)565         public int getItemViewType(int position) {
566             Header header = getItem(position);
567             return getHeaderType(header);
568         }
569 
570         @Override
areAllItemsEnabled()571         public boolean areAllItemsEnabled() {
572             return false; // because of categories
573         }
574 
575         @Override
isEnabled(int position)576         public boolean isEnabled(int position) {
577             return getItemViewType(position) != HEADER_TYPE_CATEGORY;
578         }
579 
580         @Override
getViewTypeCount()581         public int getViewTypeCount() {
582             return HEADER_TYPE_COUNT;
583         }
584 
585         @Override
hasStableIds()586         public boolean hasStableIds() {
587             return true;
588         }
589 
HeaderAdapter(Context context, List<Header> objects, AuthenticatorHelper authenticatorHelper)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
getView(int position, View convertView, ViewGroup parent)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 
resume()692         public void resume() {
693             mWifiEnabler.resume();
694             mBluetoothEnabler.resume();
695         }
696 
pause()697         public void pause() {
698             mWifiEnabler.pause();
699             mBluetoothEnabler.pause();
700         }
701     }
702 
703     @Override
onHeaderClick(Header header, int position)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
onPreferenceStartFragment(PreferenceFragment caller, Preference pref)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 
shouldUpRecreateTask(Intent targetIntent)731     public boolean shouldUpRecreateTask(Intent targetIntent) {
732         return super.shouldUpRecreateTask(new Intent(this, Settings.class));
733     }
734 
735     @Override
setListAdapter(ListAdapter adapter)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
onAccountsUpdated(Account[] accounts)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