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