2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
19 import android.accounts.Account;
20 import android.accounts.AccountManager;
21 import android.accounts.OnAccountsUpdateListener;
22 import android.app.Fragment;
23 import android.content.BroadcastReceiver;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.RestrictionEntry;
29 import android.content.SharedPreferences;
30 import android.content.pm.ActivityInfo;
31 import android.content.pm.PackageManager;
32 import android.content.pm.PackageManager.NameNotFoundException;
33 import android.graphics.drawable.Drawable;
34 import android.os.Bundle;
35 import android.os.INetworkManagementService;
36 import android.os.RemoteException;
37 import android.os.ServiceManager;
38 import android.os.UserHandle;
39 import android.os.UserManager;
40 import android.preference.Preference;
41 import android.preference.PreferenceActivity;
42 import android.preference.PreferenceFragment;
43 import android.text.TextUtils;
44 import android.util.Log;
45 import android.view.LayoutInflater;
46 import android.view.View;
47 import android.view.View.OnClickListener;
48 import android.view.ViewGroup;
49 import android.widget.ArrayAdapter;
50 import android.widget.Button;
51 import android.widget.ImageView;
52 import android.widget.ListAdapter;
53 import android.widget.Switch;
54 import android.widget.TextView;
56 import com.android.internal.util.ArrayUtils;
57 import com.android.settings.accessibility.AccessibilitySettings;
58 import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
59 import com.android.settings.ChooseLockGeneric.ChooseLockGenericFragment;
60 import com.android.settings.ChooseLockPassword.ChooseLockPasswordFragment;
61 import com.android.settings.ChooseLockPattern.ChooseLockPatternFragment;
62 import com.android.settings.accounts.AccountSyncSettings;
63 import com.android.settings.accounts.AuthenticatorHelper;
64 import com.android.settings.accounts.ManageAccountsSettings;
65 import com.android.settings.applications.AppOpsSummary;
66 import com.android.settings.applications.ManageApplications;
67 import com.android.settings.applications.ProcessStatsUi;
68 import com.android.settings.bluetooth.BluetoothEnabler;
69 import com.android.settings.bluetooth.BluetoothSettings;
70 import com.android.settings.deviceinfo.Memory;
71 import com.android.settings.deviceinfo.UsbSettings;
72 import com.android.settings.fuelgauge.PowerUsageSummary;
73 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
74 import com.android.settings.inputmethod.SpellCheckersSettings;
75 import com.android.settings.inputmethod.UserDictionaryList;
76 import com.android.settings.location.LocationSettings;
77 import com.android.settings.nfc.AndroidBeam;
78 import com.android.settings.nfc.PaymentSettings;
79 import com.android.settings.tts.TextToSpeechSettings;
80 import com.android.settings.users.AppRestrictionsFragment;
81 import com.android.settings.users.UserSettings;
82 import com.android.settings.vpn2.VpnSettings;
83 import com.android.settings.wfd.WifiDisplaySettings;
84 import com.android.settings.wifi.AdvancedWifiSettings;
85 import com.android.settings.wifi.WifiEnabler;
86 import com.android.settings.wifi.WifiSettings;
87 import com.android.settings.wifi.p2p.WifiP2pSettings;
89 import java.util.ArrayList;
90 import java.util.Collections;
91 import java.util.Comparator;
92 import java.util.HashMap;
93 import java.util.List;
96 * Top-level settings activity to handle single pane and double pane UI layout.
98 public class Settings extends PreferenceActivity
99 implements ButtonBarHandler, OnAccountsUpdateListener {
101 private static final String LOG_TAG = "Settings";
103 private static final String META_DATA_KEY_HEADER_ID =
104 "com.android.settings.TOP_LEVEL_HEADER_ID";
105 private static final String META_DATA_KEY_FRAGMENT_CLASS =
106 "com.android.settings.FRAGMENT_CLASS";
107 private static final String META_DATA_KEY_PARENT_TITLE =
108 "com.android.settings.PARENT_FRAGMENT_TITLE";
109 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
110 "com.android.settings.PARENT_FRAGMENT_CLASS";
112 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
114 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
115 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
117 private String mFragmentClass;
118 private int mTopLevelHeaderId;
119 private Header mFirstHeader;
120 private Header mCurrentHeader;
121 private Header mParentHeader;
122 private boolean mInLocalHeaderSwitch;
124 // Show only these settings for restricted users
125 private int[] SETTINGS_FOR_RESTRICTED = {
126 R.id.wireless_section,
128 R.id.bluetooth_settings,
129 R.id.data_usage_settings,
130 R.id.wireless_settings,
133 R.id.display_settings,
134 R.id.storage_settings,
135 R.id.application_settings,
136 R.id.battery_settings,
137 R.id.personal_section,
138 R.id.location_settings,
139 R.id.security_settings,
140 R.id.language_settings,
142 R.id.account_settings,
145 R.id.date_time_settings,
147 R.id.accessibility_settings,
149 R.id.nfc_payment_settings
152 private SharedPreferences mDevelopmentPreferences;
153 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
155 // TODO: Update Call Settings based on airplane mode state.
157 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
159 private AuthenticatorHelper mAuthenticatorHelper;
160 private Header mLastHeader;
161 private boolean mListeningToAccountUpdates;
163 private boolean mBatteryPresent = true;
164 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
167 public void onReceive(Context context, Intent intent) {
168 String action = intent.getAction();
169 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
170 boolean batteryPresent = Utils.isBatteryPresent(intent);
172 if (mBatteryPresent != batteryPresent) {
173 mBatteryPresent = batteryPresent;
181 protected void onCreate(Bundle savedInstanceState) {
182 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
183 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
186 mAuthenticatorHelper = new AuthenticatorHelper();
187 mAuthenticatorHelper.updateAuthDescriptions(this);
188 mAuthenticatorHelper.onAccountsUpdated(this, null);
190 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
191 Context.MODE_PRIVATE);
194 mInLocalHeaderSwitch = true;
195 super.onCreate(savedInstanceState);
196 mInLocalHeaderSwitch = false;
198 if (!onIsHidingHeaders() && onIsMultiPane()) {
199 highlightHeader(mTopLevelHeaderId);
200 // Force the title so that it doesn't get overridden by a direct launch of
201 // a specific settings screen.
202 setTitle(R.string.settings_label);
205 // Retrieve any saved state
206 if (savedInstanceState != null) {
207 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
208 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
211 // If the current header was saved, switch to it
212 if (savedInstanceState != null && mCurrentHeader != null) {
213 //switchToHeaderLocal(mCurrentHeader);
214 showBreadCrumbs(mCurrentHeader.title, null);
217 if (mParentHeader != null) {
218 setParentTitle(mParentHeader.title, null, new OnClickListener() {
220 public void onClick(View v) {
221 switchToParent(mParentHeader.fragment);
226 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
227 if (onIsMultiPane()) {
228 getActionBar().setDisplayHomeAsUpEnabled(false);
229 getActionBar().setHomeButtonEnabled(false);
234 protected void onSaveInstanceState(Bundle outState) {
235 super.onSaveInstanceState(outState);
237 // Save the current fragment, if it is the same as originally launched
238 if (mCurrentHeader != null) {
239 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
241 if (mParentHeader != null) {
242 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
247 public void onResume() {
250 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
252 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
256 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
257 mDevelopmentPreferencesListener);
259 ListAdapter listAdapter = getListAdapter();
260 if (listAdapter instanceof HeaderAdapter) {
261 ((HeaderAdapter) listAdapter).resume();
265 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
269 public void onPause() {
272 unregisterReceiver(mBatteryInfoReceiver);
274 ListAdapter listAdapter = getListAdapter();
275 if (listAdapter instanceof HeaderAdapter) {
276 ((HeaderAdapter) listAdapter).pause();
279 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
280 mDevelopmentPreferencesListener);
281 mDevelopmentPreferencesListener = null;
285 public void onDestroy() {
287 if (mListeningToAccountUpdates) {
288 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
293 public boolean onIsMultiPane() {
297 private static final String[] ENTRY_FRAGMENTS = {
298 WirelessSettings.class.getName(),
299 WifiSettings.class.getName(),
300 AdvancedWifiSettings.class.getName(),
301 BluetoothSettings.class.getName(),
302 TetherSettings.class.getName(),
303 WifiP2pSettings.class.getName(),
304 VpnSettings.class.getName(),
305 DateTimeSettings.class.getName(),
306 LocalePicker.class.getName(),
307 InputMethodAndLanguageSettings.class.getName(),
308 SpellCheckersSettings.class.getName(),
309 UserDictionaryList.class.getName(),
310 UserDictionarySettings.class.getName(),
311 SoundSettings.class.getName(),
312 DisplaySettings.class.getName(),
313 DeviceInfoSettings.class.getName(),
314 ManageApplications.class.getName(),
315 ProcessStatsUi.class.getName(),
316 NotificationStation.class.getName(),
317 AppOpsSummary.class.getName(),
318 LocationSettings.class.getName(),
319 SecuritySettings.class.getName(),
320 PrivacySettings.class.getName(),
321 DeviceAdminSettings.class.getName(),
322 AccessibilitySettings.class.getName(),
323 TextToSpeechSettings.class.getName(),
324 Memory.class.getName(),
325 DevelopmentSettings.class.getName(),
326 UsbSettings.class.getName(),
327 AndroidBeam.class.getName(),
328 WifiDisplaySettings.class.getName(),
329 PowerUsageSummary.class.getName(),
330 AccountSyncSettings.class.getName(),
331 CryptKeeperSettings.class.getName(),
332 DataUsageSummary.class.getName(),
333 DreamSettings.class.getName(),
334 UserSettings.class.getName(),
335 NotificationAccessSettings.class.getName(),
336 ManageAccountsSettings.class.getName(),
337 PrintingSettings.class.getName(),
338 TrustedCredentialsSettings.class.getName(),
339 PaymentSettings.class.getName()
343 protected boolean isValidFragment(String fragmentName) {
344 // Almost all fragments are wrapped in this,
345 // except for a few that have their own activities.
346 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
347 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
352 private void switchToHeaderLocal(Header header) {
353 mInLocalHeaderSwitch = true;
354 switchToHeader(header);
355 mInLocalHeaderSwitch = false;
359 public void switchToHeader(Header header) {
360 if (!mInLocalHeaderSwitch) {
361 mCurrentHeader = null;
362 mParentHeader = null;
364 super.switchToHeader(header);
368 * Switch to parent fragment and store the grand parent's info
369 * @param className name of the activity wrapper for the parent fragment.
371 private void switchToParent(String className) {
372 final ComponentName cn = new ComponentName(this, className);
374 final PackageManager pm = getPackageManager();
375 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
377 if (parentInfo != null && parentInfo.metaData != null) {
378 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
379 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
380 Header parentHeader = new Header();
381 parentHeader.fragment = fragmentClass;
382 parentHeader.title = fragmentTitle;
383 mCurrentHeader = parentHeader;
385 switchToHeaderLocal(parentHeader);
386 highlightHeader(mTopLevelHeaderId);
388 mParentHeader = new Header();
389 mParentHeader.fragment
390 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
391 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
393 } catch (NameNotFoundException nnfe) {
394 Log.w(LOG_TAG, "Could not find parent activity : " + className);
399 public void onNewIntent(Intent intent) {
400 super.onNewIntent(intent);
402 // If it is not launched from history, then reset to top-level
403 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
404 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
405 switchToHeaderLocal(mFirstHeader);
407 getListView().setSelectionFromTop(0, 0);
411 private void highlightHeader(int id) {
413 Integer index = mHeaderIndexMap.get(id);
415 getListView().setItemChecked(index, true);
417 getListView().smoothScrollToPosition(index);
424 public Intent getIntent() {
425 Intent superIntent = super.getIntent();
426 String startingFragment = getStartingFragmentClass(superIntent);
427 // This is called from super.onCreate, isMultiPane() is not yet reliable
428 // Do not use onIsHidingHeaders either, which relies itself on this method
429 if (startingFragment != null && !onIsMultiPane()) {
430 Intent modIntent = new Intent(superIntent);
431 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
432 Bundle args = superIntent.getExtras();
434 args = new Bundle(args);
438 args.putParcelable("intent", superIntent);
439 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
446 * Checks if the component name in the intent is different from the Settings class and
447 * returns the class name to load as a fragment.
449 protected String getStartingFragmentClass(Intent intent) {
450 if (mFragmentClass != null) return mFragmentClass;
452 String intentClass = intent.getComponent().getClassName();
453 if (intentClass.equals(getClass().getName())) return null;
455 if ("com.android.settings.ManageApplications".equals(intentClass)
456 || "com.android.settings.RunningServices".equals(intentClass)
457 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
458 // Old names of manage apps.
459 intentClass = com.android.settings.applications.ManageApplications.class.getName();
466 * Override initial header when an activity-alias is causing Settings to be launched
467 * for a specific fragment encoded in the android:name parameter.
470 public Header onGetInitialHeader() {
471 String fragmentClass = getStartingFragmentClass(super.getIntent());
472 if (fragmentClass != null) {
473 Header header = new Header();
474 header.fragment = fragmentClass;
475 header.title = getTitle();
476 header.fragmentArguments = getIntent().getExtras();
477 mCurrentHeader = header;
485 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
486 int titleRes, int shortTitleRes) {
487 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
488 titleRes, shortTitleRes);
490 // Some fragments want split ActionBar; these should stay in sync with
491 // uiOptions for fragments also defined as activities in manifest.
492 if (WifiSettings.class.getName().equals(fragmentName) ||
493 WifiP2pSettings.class.getName().equals(fragmentName) ||
494 WifiDisplaySettings.class.getName().equals(fragmentName) ||
495 BluetoothSettings.class.getName().equals(fragmentName) ||
496 DreamSettings.class.getName().equals(fragmentName) ||
497 LocationSettings.class.getName().equals(fragmentName) ||
498 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName)) {
499 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
502 intent.setClass(this, SubSettings.class);
507 * Populate the activity with the top-level headers.
510 public void onBuildHeaders(List<Header> headers) {
511 loadHeadersFromResource(R.xml.settings_headers, headers);
512 updateHeaderList(headers);
515 private void updateHeaderList(List<Header> target) {
516 final boolean showDev = mDevelopmentPreferences.getBoolean(
517 DevelopmentSettings.PREF_SHOW,
518 android.os.Build.TYPE.equals("eng"));
521 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
522 mHeaderIndexMap.clear();
523 while (i < target.size()) {
524 Header header = target.get(i);
525 // Ids are integers, so downcasting
526 int id = (int) header.id;
527 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
528 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
529 } else if (id == R.id.wifi_settings) {
530 // Remove WiFi Settings if WiFi service is not available.
531 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
534 } else if (id == R.id.bluetooth_settings) {
535 // Remove Bluetooth Settings if Bluetooth service is not available.
536 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
539 } else if (id == R.id.data_usage_settings) {
540 // Remove data usage when kernel module not enabled
541 final INetworkManagementService netManager = INetworkManagementService.Stub
542 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
544 if (!netManager.isBandwidthControlEnabled()) {
547 } catch (RemoteException e) {
550 } else if (id == R.id.battery_settings) {
551 // Remove battery settings when battery is not available. (e.g. TV)
553 if (!mBatteryPresent) {
556 } else if (id == R.id.account_settings) {
557 int headerIndex = i + 1;
558 i = insertAccountsHeaders(target, headerIndex);
559 } else if (id == R.id.user_settings) {
560 if (!UserHandle.MU_ENABLED
561 || !UserManager.supportsMultipleUsers()
562 || Utils.isMonkeyRunning()) {
565 } else if (id == R.id.nfc_payment_settings) {
566 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HCE)) {
569 } else if (id == R.id.development_settings) {
573 } else if (id == R.id.account_add) {
574 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
579 if (i < target.size() && target.get(i) == header
580 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
581 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
585 // Increment if the current one wasn't removed by the Utils code.
586 if (i < target.size() && target.get(i) == header) {
587 // Hold on to the first header, when we need to reset to the top-level
588 if (mFirstHeader == null &&
589 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
590 mFirstHeader = header;
592 mHeaderIndexMap.put(id, i);
598 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
599 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
600 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
601 for (String accountType : accountTypes) {
602 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
607 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
608 boolean skipToAccount = accounts.length == 1
609 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
610 Header accHeader = new Header();
611 accHeader.title = label;
612 if (accHeader.extras == null) {
613 accHeader.extras = new Bundle();
616 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
617 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
618 accHeader.fragment = AccountSyncSettings.class.getName();
619 accHeader.fragmentArguments = new Bundle();
620 // Need this for the icon
621 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
622 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
623 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
626 accHeader.breadCrumbTitle = label;
627 accHeader.breadCrumbShortTitle = label;
628 accHeader.fragment = ManageAccountsSettings.class.getName();
629 accHeader.fragmentArguments = new Bundle();
630 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
631 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
633 if (!isMultiPane()) {
634 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
638 accountHeaders.add(accHeader);
642 Collections.sort(accountHeaders, new Comparator<Header>() {
644 public int compare(Header h1, Header h2) {
645 return h1.title.toString().compareTo(h2.title.toString());
649 for (Header header : accountHeaders) {
650 target.add(headerIndex++, header);
652 if (!mListeningToAccountUpdates) {
653 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
654 mListeningToAccountUpdates = true;
659 private void getMetaData() {
661 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
662 PackageManager.GET_META_DATA);
663 if (ai == null || ai.metaData == null) return;
664 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
665 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
667 // Check if it has a parent specified and create a Header object
668 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
669 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
670 if (parentFragmentClass != null) {
671 mParentHeader = new Header();
672 mParentHeader.fragment = parentFragmentClass;
673 if (parentHeaderTitleRes != 0) {
674 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
677 } catch (NameNotFoundException nnfe) {
683 public boolean hasNextButton() {
684 return super.hasNextButton();
688 public Button getNextButton() {
689 return super.getNextButton();
692 private static class HeaderAdapter extends ArrayAdapter<Header> {
693 static final int HEADER_TYPE_CATEGORY = 0;
694 static final int HEADER_TYPE_NORMAL = 1;
695 static final int HEADER_TYPE_SWITCH = 2;
696 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;
698 private final WifiEnabler mWifiEnabler;
699 private final BluetoothEnabler mBluetoothEnabler;
700 private AuthenticatorHelper mAuthHelper;
702 private static class HeaderViewHolder {
709 private LayoutInflater mInflater;
711 static int getHeaderType(Header header) {
712 if (header.fragment == null && header.intent == null) {
713 return HEADER_TYPE_CATEGORY;
714 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
715 return HEADER_TYPE_SWITCH;
717 return HEADER_TYPE_NORMAL;
722 public int getItemViewType(int position) {
723 Header header = getItem(position);
724 return getHeaderType(header);
728 public boolean areAllItemsEnabled() {
729 return false; // because of categories
733 public boolean isEnabled(int position) {
734 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
738 public int getViewTypeCount() {
739 return HEADER_TYPE_COUNT;
743 public boolean hasStableIds() {
747 public HeaderAdapter(Context context, List<Header> objects,
748 AuthenticatorHelper authenticatorHelper) {
749 super(context, 0, objects);
751 mAuthHelper = authenticatorHelper;
752 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
754 // Temp Switches provided as placeholder until the adapter replaces these with actual
755 // Switches inflated from their layouts. Must be done before adapter is set in super
756 mWifiEnabler = new WifiEnabler(context, new Switch(context));
757 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
761 public View getView(int position, View convertView, ViewGroup parent) {
762 HeaderViewHolder holder;
763 Header header = getItem(position);
764 int headerType = getHeaderType(header);
767 if (convertView == null) {
768 holder = new HeaderViewHolder();
769 switch (headerType) {
770 case HEADER_TYPE_CATEGORY:
771 view = new TextView(getContext(), null,
772 android.R.attr.listSeparatorTextViewStyle);
773 holder.title = (TextView) view;
776 case HEADER_TYPE_SWITCH:
777 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
779 holder.icon = (ImageView) view.findViewById(R.id.icon);
780 holder.title = (TextView)
781 view.findViewById(com.android.internal.R.id.title);
782 holder.summary = (TextView)
783 view.findViewById(com.android.internal.R.id.summary);
784 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
787 case HEADER_TYPE_NORMAL:
788 view = mInflater.inflate(
789 R.layout.preference_header_item, parent,
791 holder.icon = (ImageView) view.findViewById(R.id.icon);
792 holder.title = (TextView)
793 view.findViewById(com.android.internal.R.id.title);
794 holder.summary = (TextView)
795 view.findViewById(com.android.internal.R.id.summary);
801 holder = (HeaderViewHolder) view.getTag();
804 // All view fields must be updated every time, because the view may be recycled
805 switch (headerType) {
806 case HEADER_TYPE_CATEGORY:
807 holder.title.setText(header.getTitle(getContext().getResources()));
810 case HEADER_TYPE_SWITCH:
811 // Would need a different treatment if the main menu had more switches
812 if (header.id == R.id.wifi_settings) {
813 mWifiEnabler.setSwitch(holder.switch_);
815 mBluetoothEnabler.setSwitch(holder.switch_);
817 // No break, fall through on purpose to update common fields
820 case HEADER_TYPE_NORMAL:
821 if (header.extras != null
822 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
823 String accType = header.extras.getString(
824 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
825 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
826 lp.width = getContext().getResources().getDimensionPixelSize(
827 R.dimen.header_icon_width);
828 lp.height = lp.width;
829 holder.icon.setLayoutParams(lp);
830 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
831 holder.icon.setImageDrawable(icon);
833 holder.icon.setImageResource(header.iconRes);
835 holder.title.setText(header.getTitle(getContext().getResources()));
836 CharSequence summary = header.getSummary(getContext().getResources());
837 if (!TextUtils.isEmpty(summary)) {
838 holder.summary.setVisibility(View.VISIBLE);
839 holder.summary.setText(summary);
841 holder.summary.setVisibility(View.GONE);
849 public void resume() {
850 mWifiEnabler.resume();
851 mBluetoothEnabler.resume();
854 public void pause() {
855 mWifiEnabler.pause();
856 mBluetoothEnabler.pause();
861 public void onHeaderClick(Header header, int position) {
862 boolean revert = false;
863 if (header.id == R.id.account_add) {
867 super.onHeaderClick(header, position);
869 if (revert && mLastHeader != null) {
870 highlightHeader((int) mLastHeader.id);
872 mLastHeader = header;
877 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
878 // Override the fragment title for Wallpaper settings
879 int titleRes = pref.getTitleRes();
880 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
881 titleRes = R.string.wallpaper_settings_fragment_title;
882 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
883 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
884 if (UserManager.get(this).isLinkedUser()) {
885 titleRes = R.string.profile_info_settings_title;
887 titleRes = R.string.user_info_settings_title;
890 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
896 public boolean shouldUpRecreateTask(Intent targetIntent) {
897 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
901 public void setListAdapter(ListAdapter adapter) {
902 if (adapter == null) {
903 super.setListAdapter(null);
905 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper));
910 public void onAccountsUpdated(Account[] accounts) {
911 // TODO: watch for package upgrades to invalidate cache; see 7206643
912 mAuthenticatorHelper.updateAuthDescriptions(this);
913 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
918 * Settings subclasses for launching independently.
920 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
921 public static class WirelessSettingsActivity extends Settings { /* empty */ }
922 public static class TetherSettingsActivity extends Settings { /* empty */ }
923 public static class VpnSettingsActivity extends Settings { /* empty */ }
924 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
925 public static class StorageSettingsActivity extends Settings { /* empty */ }
926 public static class WifiSettingsActivity extends Settings { /* empty */ }
927 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
928 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
929 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
930 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
931 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
932 public static class LocalePickerActivity extends Settings { /* empty */ }
933 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
934 public static class SoundSettingsActivity extends Settings { /* empty */ }
935 public static class DisplaySettingsActivity extends Settings { /* empty */ }
936 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
937 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
938 public static class ManageApplicationsActivity extends Settings { /* empty */ }
939 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
940 public static class StorageUseActivity extends Settings { /* empty */ }
941 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
942 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
943 public static class SecuritySettingsActivity extends Settings { /* empty */ }
944 public static class LocationSettingsActivity extends Settings { /* empty */ }
945 public static class PrivacySettingsActivity extends Settings { /* empty */ }
946 public static class RunningServicesActivity extends Settings { /* empty */ }
947 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
948 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
949 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
950 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
951 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
952 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
953 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
954 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
955 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
956 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
957 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
958 public static class DreamSettingsActivity extends Settings { /* empty */ }
959 public static class NotificationStationActivity extends Settings { /* empty */ }
960 public static class UserSettingsActivity extends Settings { /* empty */ }
961 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
962 public static class UsbSettingsActivity extends Settings { /* empty */ }
963 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
964 public static class PaymentSettingsActivity extends Settings { /* empty */ }