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.content.BroadcastReceiver;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.SharedPreferences;
28 import android.content.pm.ActivityInfo;
29 import android.content.pm.PackageManager;
30 import android.content.pm.PackageManager.NameNotFoundException;
31 import android.graphics.drawable.Drawable;
32 import android.os.Bundle;
33 import android.os.INetworkManagementService;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
36 import android.os.UserHandle;
37 import android.os.UserManager;
38 import android.preference.Preference;
39 import android.preference.PreferenceActivity;
40 import android.preference.PreferenceFragment;
41 import android.text.TextUtils;
42 import android.util.Log;
43 import android.view.LayoutInflater;
44 import android.view.View;
45 import android.view.View.OnClickListener;
46 import android.view.ViewGroup;
47 import android.widget.ArrayAdapter;
48 import android.widget.Button;
49 import android.widget.ImageView;
50 import android.widget.ListAdapter;
51 import android.widget.Switch;
52 import android.widget.TextView;
54 import com.android.internal.util.ArrayUtils;
55 import com.android.settings.accessibility.AccessibilitySettings;
56 import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
57 import com.android.settings.accessibility.ToggleCaptioningPreferenceFragment;
58 import com.android.settings.accounts.AccountSyncSettings;
59 import com.android.settings.accounts.AuthenticatorHelper;
60 import com.android.settings.accounts.ManageAccountsSettings;
61 import com.android.settings.applications.AppOpsSummary;
62 import com.android.settings.applications.ManageApplications;
63 import com.android.settings.applications.ProcessStatsUi;
64 import com.android.settings.bluetooth.BluetoothEnabler;
65 import com.android.settings.bluetooth.BluetoothSettings;
66 import com.android.settings.deviceinfo.Memory;
67 import com.android.settings.deviceinfo.UsbSettings;
68 import com.android.settings.fuelgauge.PowerUsageSummary;
69 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
70 import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
71 import com.android.settings.inputmethod.SpellCheckersSettings;
72 import com.android.settings.inputmethod.UserDictionaryList;
73 import com.android.settings.location.LocationSettings;
74 import com.android.settings.nfc.AndroidBeam;
75 import com.android.settings.nfc.PaymentSettings;
76 import com.android.settings.print.PrintServiceSettingsFragment;
77 import com.android.settings.print.PrintSettingsFragment;
78 import com.android.settings.tts.TextToSpeechSettings;
79 import com.android.settings.users.UserSettings;
80 import com.android.settings.vpn2.VpnSettings;
81 import com.android.settings.wfd.WifiDisplaySettings;
82 import com.android.settings.wifi.AdvancedWifiSettings;
83 import com.android.settings.wifi.WifiEnabler;
84 import com.android.settings.wifi.WifiSettings;
85 import com.android.settings.wifi.p2p.WifiP2pSettings;
87 import java.util.ArrayList;
88 import java.util.Collections;
89 import java.util.Comparator;
90 import java.util.HashMap;
91 import java.util.List;
94 * Top-level settings activity to handle single pane and double pane UI layout.
96 public class Settings extends PreferenceActivity
97 implements ButtonBarHandler, OnAccountsUpdateListener {
99 private static final String LOG_TAG = "Settings";
101 private static final String META_DATA_KEY_HEADER_ID =
102 "com.android.settings.TOP_LEVEL_HEADER_ID";
103 private static final String META_DATA_KEY_FRAGMENT_CLASS =
104 "com.android.settings.FRAGMENT_CLASS";
105 private static final String META_DATA_KEY_PARENT_TITLE =
106 "com.android.settings.PARENT_FRAGMENT_TITLE";
107 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
108 "com.android.settings.PARENT_FRAGMENT_CLASS";
110 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
112 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
113 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
115 private String mFragmentClass;
116 private int mTopLevelHeaderId;
117 private Header mFirstHeader;
118 private Header mCurrentHeader;
119 private Header mParentHeader;
120 private boolean mInLocalHeaderSwitch;
122 // Show only these settings for restricted users
123 private int[] SETTINGS_FOR_RESTRICTED = {
124 R.id.wireless_section,
126 R.id.bluetooth_settings,
127 R.id.data_usage_settings,
128 R.id.wireless_settings,
131 R.id.display_settings,
132 R.id.storage_settings,
133 R.id.application_settings,
134 R.id.battery_settings,
135 R.id.personal_section,
136 R.id.location_settings,
137 R.id.security_settings,
138 R.id.language_settings,
140 R.id.account_settings,
143 R.id.date_time_settings,
145 R.id.accessibility_settings,
147 R.id.nfc_payment_settings
150 private SharedPreferences mDevelopmentPreferences;
151 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
153 // TODO: Update Call Settings based on airplane mode state.
155 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
157 private AuthenticatorHelper mAuthenticatorHelper;
158 private Header mLastHeader;
159 private boolean mListeningToAccountUpdates;
161 private boolean mBatteryPresent = true;
162 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
165 public void onReceive(Context context, Intent intent) {
166 String action = intent.getAction();
167 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
168 boolean batteryPresent = Utils.isBatteryPresent(intent);
170 if (mBatteryPresent != batteryPresent) {
171 mBatteryPresent = batteryPresent;
179 protected void onCreate(Bundle savedInstanceState) {
180 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
181 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
184 mAuthenticatorHelper = new AuthenticatorHelper();
185 mAuthenticatorHelper.updateAuthDescriptions(this);
186 mAuthenticatorHelper.onAccountsUpdated(this, null);
188 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
189 Context.MODE_PRIVATE);
192 mInLocalHeaderSwitch = true;
193 super.onCreate(savedInstanceState);
194 mInLocalHeaderSwitch = false;
196 if (!onIsHidingHeaders() && onIsMultiPane()) {
197 highlightHeader(mTopLevelHeaderId);
198 // Force the title so that it doesn't get overridden by a direct launch of
199 // a specific settings screen.
200 setTitle(R.string.settings_label);
203 // Retrieve any saved state
204 if (savedInstanceState != null) {
205 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
206 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
209 // If the current header was saved, switch to it
210 if (savedInstanceState != null && mCurrentHeader != null) {
211 //switchToHeaderLocal(mCurrentHeader);
212 showBreadCrumbs(mCurrentHeader.title, null);
215 if (mParentHeader != null) {
216 setParentTitle(mParentHeader.title, null, new OnClickListener() {
218 public void onClick(View v) {
219 switchToParent(mParentHeader.fragment);
224 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
225 if (onIsMultiPane()) {
226 getActionBar().setDisplayHomeAsUpEnabled(false);
227 getActionBar().setHomeButtonEnabled(false);
232 protected void onSaveInstanceState(Bundle outState) {
233 super.onSaveInstanceState(outState);
235 // Save the current fragment, if it is the same as originally launched
236 if (mCurrentHeader != null) {
237 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
239 if (mParentHeader != null) {
240 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
245 public void onResume() {
248 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
250 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
254 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
255 mDevelopmentPreferencesListener);
257 ListAdapter listAdapter = getListAdapter();
258 if (listAdapter instanceof HeaderAdapter) {
259 ((HeaderAdapter) listAdapter).resume();
263 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
267 public void onPause() {
270 unregisterReceiver(mBatteryInfoReceiver);
272 ListAdapter listAdapter = getListAdapter();
273 if (listAdapter instanceof HeaderAdapter) {
274 ((HeaderAdapter) listAdapter).pause();
277 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
278 mDevelopmentPreferencesListener);
279 mDevelopmentPreferencesListener = null;
283 public void onDestroy() {
285 if (mListeningToAccountUpdates) {
286 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
291 public boolean onIsMultiPane() {
295 private static final String[] ENTRY_FRAGMENTS = {
296 WirelessSettings.class.getName(),
297 WifiSettings.class.getName(),
298 AdvancedWifiSettings.class.getName(),
299 BluetoothSettings.class.getName(),
300 TetherSettings.class.getName(),
301 WifiP2pSettings.class.getName(),
302 VpnSettings.class.getName(),
303 DateTimeSettings.class.getName(),
304 LocalePicker.class.getName(),
305 InputMethodAndLanguageSettings.class.getName(),
306 SpellCheckersSettings.class.getName(),
307 UserDictionaryList.class.getName(),
308 UserDictionarySettings.class.getName(),
309 SoundSettings.class.getName(),
310 DisplaySettings.class.getName(),
311 DeviceInfoSettings.class.getName(),
312 ManageApplications.class.getName(),
313 ProcessStatsUi.class.getName(),
314 NotificationStation.class.getName(),
315 AppOpsSummary.class.getName(),
316 LocationSettings.class.getName(),
317 SecuritySettings.class.getName(),
318 PrivacySettings.class.getName(),
319 DeviceAdminSettings.class.getName(),
320 AccessibilitySettings.class.getName(),
321 ToggleCaptioningPreferenceFragment.class.getName(),
322 TextToSpeechSettings.class.getName(),
323 Memory.class.getName(),
324 DevelopmentSettings.class.getName(),
325 UsbSettings.class.getName(),
326 AndroidBeam.class.getName(),
327 WifiDisplaySettings.class.getName(),
328 PowerUsageSummary.class.getName(),
329 AccountSyncSettings.class.getName(),
330 CryptKeeperSettings.class.getName(),
331 DataUsageSummary.class.getName(),
332 DreamSettings.class.getName(),
333 UserSettings.class.getName(),
334 NotificationAccessSettings.class.getName(),
335 ManageAccountsSettings.class.getName(),
336 PrintSettingsFragment.class.getName(),
337 TrustedCredentialsSettings.class.getName(),
338 PaymentSettings.class.getName(),
339 KeyboardLayoutPickerFragment.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 PrintSettingsFragment.class.getName().equals(fragmentName) ||
500 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
501 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
504 intent.setClass(this, SubSettings.class);
509 * Populate the activity with the top-level headers.
512 public void onBuildHeaders(List<Header> headers) {
513 loadHeadersFromResource(R.xml.settings_headers, headers);
514 updateHeaderList(headers);
517 private void updateHeaderList(List<Header> target) {
518 final boolean showDev = mDevelopmentPreferences.getBoolean(
519 DevelopmentSettings.PREF_SHOW,
520 android.os.Build.TYPE.equals("eng"));
523 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
524 mHeaderIndexMap.clear();
525 while (i < target.size()) {
526 Header header = target.get(i);
527 // Ids are integers, so downcasting
528 int id = (int) header.id;
529 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
530 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
531 } else if (id == R.id.wifi_settings) {
532 // Remove WiFi Settings if WiFi service is not available.
533 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
536 } else if (id == R.id.bluetooth_settings) {
537 // Remove Bluetooth Settings if Bluetooth service is not available.
538 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
541 } else if (id == R.id.data_usage_settings) {
542 // Remove data usage when kernel module not enabled
543 final INetworkManagementService netManager = INetworkManagementService.Stub
544 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
546 if (!netManager.isBandwidthControlEnabled()) {
549 } catch (RemoteException e) {
552 } else if (id == R.id.battery_settings) {
553 // Remove battery settings when battery is not available. (e.g. TV)
555 if (!mBatteryPresent) {
558 } else if (id == R.id.account_settings) {
559 int headerIndex = i + 1;
560 i = insertAccountsHeaders(target, headerIndex);
561 } else if (id == R.id.user_settings) {
562 if (!UserHandle.MU_ENABLED
563 || !UserManager.supportsMultipleUsers()
564 || Utils.isMonkeyRunning()) {
567 } else if (id == R.id.nfc_payment_settings) {
568 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HCE)) {
571 } else if (id == R.id.development_settings) {
575 } else if (id == R.id.account_add) {
576 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
581 if (i < target.size() && target.get(i) == header
582 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
583 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
587 // Increment if the current one wasn't removed by the Utils code.
588 if (i < target.size() && target.get(i) == header) {
589 // Hold on to the first header, when we need to reset to the top-level
590 if (mFirstHeader == null &&
591 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
592 mFirstHeader = header;
594 mHeaderIndexMap.put(id, i);
600 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
601 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
602 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
603 for (String accountType : accountTypes) {
604 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
609 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
610 boolean skipToAccount = accounts.length == 1
611 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
612 Header accHeader = new Header();
613 accHeader.title = label;
614 if (accHeader.extras == null) {
615 accHeader.extras = new Bundle();
618 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
619 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
620 accHeader.fragment = AccountSyncSettings.class.getName();
621 accHeader.fragmentArguments = new Bundle();
622 // Need this for the icon
623 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
624 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
625 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
628 accHeader.breadCrumbTitle = label;
629 accHeader.breadCrumbShortTitle = label;
630 accHeader.fragment = ManageAccountsSettings.class.getName();
631 accHeader.fragmentArguments = new Bundle();
632 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
633 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
635 if (!isMultiPane()) {
636 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
640 accountHeaders.add(accHeader);
644 Collections.sort(accountHeaders, new Comparator<Header>() {
646 public int compare(Header h1, Header h2) {
647 return h1.title.toString().compareTo(h2.title.toString());
651 for (Header header : accountHeaders) {
652 target.add(headerIndex++, header);
654 if (!mListeningToAccountUpdates) {
655 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
656 mListeningToAccountUpdates = true;
661 private void getMetaData() {
663 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
664 PackageManager.GET_META_DATA);
665 if (ai == null || ai.metaData == null) return;
666 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
667 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
669 // Check if it has a parent specified and create a Header object
670 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
671 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
672 if (parentFragmentClass != null) {
673 mParentHeader = new Header();
674 mParentHeader.fragment = parentFragmentClass;
675 if (parentHeaderTitleRes != 0) {
676 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
679 } catch (NameNotFoundException nnfe) {
685 public boolean hasNextButton() {
686 return super.hasNextButton();
690 public Button getNextButton() {
691 return super.getNextButton();
694 private static class HeaderAdapter extends ArrayAdapter<Header> {
695 static final int HEADER_TYPE_CATEGORY = 0;
696 static final int HEADER_TYPE_NORMAL = 1;
697 static final int HEADER_TYPE_SWITCH = 2;
698 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;
700 private final WifiEnabler mWifiEnabler;
701 private final BluetoothEnabler mBluetoothEnabler;
702 private AuthenticatorHelper mAuthHelper;
704 private static class HeaderViewHolder {
711 private LayoutInflater mInflater;
713 static int getHeaderType(Header header) {
714 if (header.fragment == null && header.intent == null) {
715 return HEADER_TYPE_CATEGORY;
716 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
717 return HEADER_TYPE_SWITCH;
719 return HEADER_TYPE_NORMAL;
724 public int getItemViewType(int position) {
725 Header header = getItem(position);
726 return getHeaderType(header);
730 public boolean areAllItemsEnabled() {
731 return false; // because of categories
735 public boolean isEnabled(int position) {
736 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
740 public int getViewTypeCount() {
741 return HEADER_TYPE_COUNT;
745 public boolean hasStableIds() {
749 public HeaderAdapter(Context context, List<Header> objects,
750 AuthenticatorHelper authenticatorHelper) {
751 super(context, 0, objects);
753 mAuthHelper = authenticatorHelper;
754 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
756 // Temp Switches provided as placeholder until the adapter replaces these with actual
757 // Switches inflated from their layouts. Must be done before adapter is set in super
758 mWifiEnabler = new WifiEnabler(context, new Switch(context));
759 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
763 public View getView(int position, View convertView, ViewGroup parent) {
764 HeaderViewHolder holder;
765 Header header = getItem(position);
766 int headerType = getHeaderType(header);
769 if (convertView == null) {
770 holder = new HeaderViewHolder();
771 switch (headerType) {
772 case HEADER_TYPE_CATEGORY:
773 view = new TextView(getContext(), null,
774 android.R.attr.listSeparatorTextViewStyle);
775 holder.title = (TextView) view;
778 case HEADER_TYPE_SWITCH:
779 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
781 holder.icon = (ImageView) view.findViewById(R.id.icon);
782 holder.title = (TextView)
783 view.findViewById(com.android.internal.R.id.title);
784 holder.summary = (TextView)
785 view.findViewById(com.android.internal.R.id.summary);
786 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
789 case HEADER_TYPE_NORMAL:
790 view = mInflater.inflate(
791 R.layout.preference_header_item, parent,
793 holder.icon = (ImageView) view.findViewById(R.id.icon);
794 holder.title = (TextView)
795 view.findViewById(com.android.internal.R.id.title);
796 holder.summary = (TextView)
797 view.findViewById(com.android.internal.R.id.summary);
803 holder = (HeaderViewHolder) view.getTag();
806 // All view fields must be updated every time, because the view may be recycled
807 switch (headerType) {
808 case HEADER_TYPE_CATEGORY:
809 holder.title.setText(header.getTitle(getContext().getResources()));
812 case HEADER_TYPE_SWITCH:
813 // Would need a different treatment if the main menu had more switches
814 if (header.id == R.id.wifi_settings) {
815 mWifiEnabler.setSwitch(holder.switch_);
817 mBluetoothEnabler.setSwitch(holder.switch_);
819 // No break, fall through on purpose to update common fields
822 case HEADER_TYPE_NORMAL:
823 if (header.extras != null
824 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
825 String accType = header.extras.getString(
826 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
827 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
828 lp.width = getContext().getResources().getDimensionPixelSize(
829 R.dimen.header_icon_width);
830 lp.height = lp.width;
831 holder.icon.setLayoutParams(lp);
832 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
833 holder.icon.setImageDrawable(icon);
835 holder.icon.setImageResource(header.iconRes);
837 holder.title.setText(header.getTitle(getContext().getResources()));
838 CharSequence summary = header.getSummary(getContext().getResources());
839 if (!TextUtils.isEmpty(summary)) {
840 holder.summary.setVisibility(View.VISIBLE);
841 holder.summary.setText(summary);
843 holder.summary.setVisibility(View.GONE);
851 public void resume() {
852 mWifiEnabler.resume();
853 mBluetoothEnabler.resume();
856 public void pause() {
857 mWifiEnabler.pause();
858 mBluetoothEnabler.pause();
863 public void onHeaderClick(Header header, int position) {
864 boolean revert = false;
865 if (header.id == R.id.account_add) {
869 super.onHeaderClick(header, position);
871 if (revert && mLastHeader != null) {
872 highlightHeader((int) mLastHeader.id);
874 mLastHeader = header;
879 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
880 // Override the fragment title for Wallpaper settings
881 int titleRes = pref.getTitleRes();
882 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
883 titleRes = R.string.wallpaper_settings_fragment_title;
884 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
885 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
886 if (UserManager.get(this).isLinkedUser()) {
887 titleRes = R.string.profile_info_settings_title;
889 titleRes = R.string.user_info_settings_title;
892 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
898 public boolean shouldUpRecreateTask(Intent targetIntent) {
899 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
903 public void setListAdapter(ListAdapter adapter) {
904 if (adapter == null) {
905 super.setListAdapter(null);
907 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper));
912 public void onAccountsUpdated(Account[] accounts) {
913 // TODO: watch for package upgrades to invalidate cache; see 7206643
914 mAuthenticatorHelper.updateAuthDescriptions(this);
915 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
920 * Settings subclasses for launching independently.
922 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
923 public static class WirelessSettingsActivity extends Settings { /* empty */ }
924 public static class TetherSettingsActivity extends Settings { /* empty */ }
925 public static class VpnSettingsActivity extends Settings { /* empty */ }
926 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
927 public static class StorageSettingsActivity extends Settings { /* empty */ }
928 public static class WifiSettingsActivity extends Settings { /* empty */ }
929 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
930 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
931 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
932 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
933 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
934 public static class LocalePickerActivity extends Settings { /* empty */ }
935 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
936 public static class SoundSettingsActivity extends Settings { /* empty */ }
937 public static class DisplaySettingsActivity extends Settings { /* empty */ }
938 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
939 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
940 public static class ManageApplicationsActivity extends Settings { /* empty */ }
941 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
942 public static class StorageUseActivity extends Settings { /* empty */ }
943 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
944 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
945 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
946 public static class SecuritySettingsActivity extends Settings { /* empty */ }
947 public static class LocationSettingsActivity extends Settings { /* empty */ }
948 public static class PrivacySettingsActivity extends Settings { /* empty */ }
949 public static class RunningServicesActivity extends Settings { /* empty */ }
950 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
951 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
952 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
953 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
954 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
955 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
956 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
957 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
958 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
959 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
960 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
961 public static class DreamSettingsActivity extends Settings { /* empty */ }
962 public static class NotificationStationActivity extends Settings { /* empty */ }
963 public static class UserSettingsActivity extends Settings { /* empty */ }
964 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
965 public static class UsbSettingsActivity extends Settings { /* empty */ }
966 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
967 public static class PaymentSettingsActivity extends Settings { /* empty */ }
968 public static class PrintSettingsActivity extends Settings { /* empty */ }