Settings.java revision c28af52e596230e53e910078a8474e19fea6ed57
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
17package com.android.settings;
18
19import com.android.internal.util.ArrayUtils;
20import com.android.settings.accounts.AccountSyncSettings;
21import com.android.settings.accounts.AuthenticatorHelper;
22import com.android.settings.accounts.ManageAccountsSettings;
23import com.android.settings.applications.ManageApplications;
24import com.android.settings.bluetooth.BluetoothEnabler;
25import com.android.settings.deviceinfo.Memory;
26import com.android.settings.fuelgauge.PowerUsageSummary;
27import com.android.settings.wifi.WifiEnabler;
28
29import android.accounts.Account;
30import android.accounts.AccountManager;
31import android.accounts.OnAccountsUpdateListener;
32import android.content.ComponentName;
33import android.content.Context;
34import android.content.Intent;
35import android.content.pm.ActivityInfo;
36import android.content.pm.PackageManager;
37import android.content.pm.PackageManager.NameNotFoundException;
38import android.graphics.drawable.Drawable;
39import android.os.Bundle;
40import android.os.INetworkManagementService;
41import android.os.RemoteException;
42import android.os.ServiceManager;
43import android.os.UserId;
44import android.preference.Preference;
45import android.preference.PreferenceActivity;
46import android.preference.PreferenceActivity.Header;
47import android.preference.PreferenceFragment;
48import android.text.TextUtils;
49import android.util.Log;
50import android.view.LayoutInflater;
51import android.view.View;
52import android.view.View.OnClickListener;
53import android.view.ViewGroup;
54import android.widget.ArrayAdapter;
55import android.widget.BaseAdapter;
56import android.widget.Button;
57import android.widget.ImageView;
58import android.widget.ListAdapter;
59import android.widget.Switch;
60import android.widget.TextView;
61
62import java.util.ArrayList;
63import java.util.Collections;
64import java.util.Comparator;
65import java.util.HashMap;
66import java.util.List;
67
68/**
69 * Top-level settings activity to handle single pane and double pane UI layout.
70 */
71public 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