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