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.KeyboardLayoutPickerFragment;
75 import com.android.settings.inputmethod.SpellCheckersSettings;
76 import com.android.settings.inputmethod.UserDictionaryList;
77 import com.android.settings.location.LocationSettings;
78 import com.android.settings.nfc.AndroidBeam;
79 import com.android.settings.nfc.PaymentSettings;
80 import com.android.settings.tts.TextToSpeechSettings;
81 import com.android.settings.users.AppRestrictionsFragment;
82 import com.android.settings.users.UserSettings;
83 import com.android.settings.vpn2.VpnSettings;
84 import com.android.settings.wfd.WifiDisplaySettings;
85 import com.android.settings.wifi.AdvancedWifiSettings;
86 import com.android.settings.wifi.WifiEnabler;
87 import com.android.settings.wifi.WifiSettings;
88 import com.android.settings.wifi.p2p.WifiP2pSettings;
90 import java.util.ArrayList;
91 import java.util.Collections;
92 import java.util.Comparator;
93 import java.util.HashMap;
94 import java.util.List;
97 * Top-level settings activity to handle single pane and double pane UI layout.
99 public class Settings extends PreferenceActivity
100 implements ButtonBarHandler, OnAccountsUpdateListener {
102 private static final String LOG_TAG = "Settings";
104 private static final String META_DATA_KEY_HEADER_ID =
105 "com.android.settings.TOP_LEVEL_HEADER_ID";
106 private static final String META_DATA_KEY_FRAGMENT_CLASS =
107 "com.android.settings.FRAGMENT_CLASS";
108 private static final String META_DATA_KEY_PARENT_TITLE =
109 "com.android.settings.PARENT_FRAGMENT_TITLE";
110 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
111 "com.android.settings.PARENT_FRAGMENT_CLASS";
113 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
115 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
116 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
118 private String mFragmentClass;
119 private int mTopLevelHeaderId;
120 private Header mFirstHeader;
121 private Header mCurrentHeader;
122 private Header mParentHeader;
123 private boolean mInLocalHeaderSwitch;
125 // Show only these settings for restricted users
126 private int[] SETTINGS_FOR_RESTRICTED = {
127 R.id.wireless_section,
129 R.id.bluetooth_settings,
130 R.id.data_usage_settings,
131 R.id.wireless_settings,
134 R.id.display_settings,
135 R.id.storage_settings,
136 R.id.application_settings,
137 R.id.battery_settings,
138 R.id.personal_section,
139 R.id.location_settings,
140 R.id.security_settings,
141 R.id.language_settings,
143 R.id.account_settings,
146 R.id.date_time_settings,
148 R.id.accessibility_settings,
150 R.id.nfc_payment_settings
153 private SharedPreferences mDevelopmentPreferences;
154 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
156 // TODO: Update Call Settings based on airplane mode state.
158 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
160 private AuthenticatorHelper mAuthenticatorHelper;
161 private Header mLastHeader;
162 private boolean mListeningToAccountUpdates;
164 private boolean mBatteryPresent = true;
165 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
168 public void onReceive(Context context, Intent intent) {
169 String action = intent.getAction();
170 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
171 boolean batteryPresent = Utils.isBatteryPresent(intent);
173 if (mBatteryPresent != batteryPresent) {
174 mBatteryPresent = batteryPresent;
182 protected void onCreate(Bundle savedInstanceState) {
183 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
184 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
187 mAuthenticatorHelper = new AuthenticatorHelper();
188 mAuthenticatorHelper.updateAuthDescriptions(this);
189 mAuthenticatorHelper.onAccountsUpdated(this, null);
191 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
192 Context.MODE_PRIVATE);
195 mInLocalHeaderSwitch = true;
196 super.onCreate(savedInstanceState);
197 mInLocalHeaderSwitch = false;
199 if (!onIsHidingHeaders() && onIsMultiPane()) {
200 highlightHeader(mTopLevelHeaderId);
201 // Force the title so that it doesn't get overridden by a direct launch of
202 // a specific settings screen.
203 setTitle(R.string.settings_label);
206 // Retrieve any saved state
207 if (savedInstanceState != null) {
208 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
209 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
212 // If the current header was saved, switch to it
213 if (savedInstanceState != null && mCurrentHeader != null) {
214 //switchToHeaderLocal(mCurrentHeader);
215 showBreadCrumbs(mCurrentHeader.title, null);
218 if (mParentHeader != null) {
219 setParentTitle(mParentHeader.title, null, new OnClickListener() {
221 public void onClick(View v) {
222 switchToParent(mParentHeader.fragment);
227 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
228 if (onIsMultiPane()) {
229 getActionBar().setDisplayHomeAsUpEnabled(false);
230 getActionBar().setHomeButtonEnabled(false);
235 protected void onSaveInstanceState(Bundle outState) {
236 super.onSaveInstanceState(outState);
238 // Save the current fragment, if it is the same as originally launched
239 if (mCurrentHeader != null) {
240 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
242 if (mParentHeader != null) {
243 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
248 public void onResume() {
251 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
253 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
257 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
258 mDevelopmentPreferencesListener);
260 ListAdapter listAdapter = getListAdapter();
261 if (listAdapter instanceof HeaderAdapter) {
262 ((HeaderAdapter) listAdapter).resume();
266 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
270 public void onPause() {
273 unregisterReceiver(mBatteryInfoReceiver);
275 ListAdapter listAdapter = getListAdapter();
276 if (listAdapter instanceof HeaderAdapter) {
277 ((HeaderAdapter) listAdapter).pause();
280 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
281 mDevelopmentPreferencesListener);
282 mDevelopmentPreferencesListener = null;
286 public void onDestroy() {
288 if (mListeningToAccountUpdates) {
289 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
294 public boolean onIsMultiPane() {
298 private static final String[] ENTRY_FRAGMENTS = {
299 WirelessSettings.class.getName(),
300 WifiSettings.class.getName(),
301 AdvancedWifiSettings.class.getName(),
302 BluetoothSettings.class.getName(),
303 TetherSettings.class.getName(),
304 WifiP2pSettings.class.getName(),
305 VpnSettings.class.getName(),
306 DateTimeSettings.class.getName(),
307 LocalePicker.class.getName(),
308 InputMethodAndLanguageSettings.class.getName(),
309 SpellCheckersSettings.class.getName(),
310 UserDictionaryList.class.getName(),
311 UserDictionarySettings.class.getName(),
312 SoundSettings.class.getName(),
313 DisplaySettings.class.getName(),
314 DeviceInfoSettings.class.getName(),
315 ManageApplications.class.getName(),
316 ProcessStatsUi.class.getName(),
317 NotificationStation.class.getName(),
318 AppOpsSummary.class.getName(),
319 LocationSettings.class.getName(),
320 SecuritySettings.class.getName(),
321 PrivacySettings.class.getName(),
322 DeviceAdminSettings.class.getName(),
323 AccessibilitySettings.class.getName(),
324 TextToSpeechSettings.class.getName(),
325 Memory.class.getName(),
326 DevelopmentSettings.class.getName(),
327 UsbSettings.class.getName(),
328 AndroidBeam.class.getName(),
329 WifiDisplaySettings.class.getName(),
330 PowerUsageSummary.class.getName(),
331 AccountSyncSettings.class.getName(),
332 CryptKeeperSettings.class.getName(),
333 DataUsageSummary.class.getName(),
334 DreamSettings.class.getName(),
335 UserSettings.class.getName(),
336 NotificationAccessSettings.class.getName(),
337 ManageAccountsSettings.class.getName(),
338 PrintingSettings.class.getName(),
339 TrustedCredentialsSettings.class.getName(),
340 PaymentSettings.class.getName(),
341 KeyboardLayoutPickerFragment.class.getName()
345 protected boolean isValidFragment(String fragmentName) {
346 // Almost all fragments are wrapped in this,
347 // except for a few that have their own activities.
348 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
349 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
354 private void switchToHeaderLocal(Header header) {
355 mInLocalHeaderSwitch = true;
356 switchToHeader(header);
357 mInLocalHeaderSwitch = false;
361 public void switchToHeader(Header header) {
362 if (!mInLocalHeaderSwitch) {
363 mCurrentHeader = null;
364 mParentHeader = null;
366 super.switchToHeader(header);
370 * Switch to parent fragment and store the grand parent's info
371 * @param className name of the activity wrapper for the parent fragment.
373 private void switchToParent(String className) {
374 final ComponentName cn = new ComponentName(this, className);
376 final PackageManager pm = getPackageManager();
377 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
379 if (parentInfo != null && parentInfo.metaData != null) {
380 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
381 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
382 Header parentHeader = new Header();
383 parentHeader.fragment = fragmentClass;
384 parentHeader.title = fragmentTitle;
385 mCurrentHeader = parentHeader;
387 switchToHeaderLocal(parentHeader);
388 highlightHeader(mTopLevelHeaderId);
390 mParentHeader = new Header();
391 mParentHeader.fragment
392 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
393 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
395 } catch (NameNotFoundException nnfe) {
396 Log.w(LOG_TAG, "Could not find parent activity : " + className);
401 public void onNewIntent(Intent intent) {
402 super.onNewIntent(intent);
404 // If it is not launched from history, then reset to top-level
405 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
406 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
407 switchToHeaderLocal(mFirstHeader);
409 getListView().setSelectionFromTop(0, 0);
413 private void highlightHeader(int id) {
415 Integer index = mHeaderIndexMap.get(id);
417 getListView().setItemChecked(index, true);
419 getListView().smoothScrollToPosition(index);
426 public Intent getIntent() {
427 Intent superIntent = super.getIntent();
428 String startingFragment = getStartingFragmentClass(superIntent);
429 // This is called from super.onCreate, isMultiPane() is not yet reliable
430 // Do not use onIsHidingHeaders either, which relies itself on this method
431 if (startingFragment != null && !onIsMultiPane()) {
432 Intent modIntent = new Intent(superIntent);
433 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
434 Bundle args = superIntent.getExtras();
436 args = new Bundle(args);
440 args.putParcelable("intent", superIntent);
441 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
448 * Checks if the component name in the intent is different from the Settings class and
449 * returns the class name to load as a fragment.
451 protected String getStartingFragmentClass(Intent intent) {
452 if (mFragmentClass != null) return mFragmentClass;
454 String intentClass = intent.getComponent().getClassName();
455 if (intentClass.equals(getClass().getName())) return null;
457 if ("com.android.settings.ManageApplications".equals(intentClass)
458 || "com.android.settings.RunningServices".equals(intentClass)
459 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
460 // Old names of manage apps.
461 intentClass = com.android.settings.applications.ManageApplications.class.getName();
468 * Override initial header when an activity-alias is causing Settings to be launched
469 * for a specific fragment encoded in the android:name parameter.
472 public Header onGetInitialHeader() {
473 String fragmentClass = getStartingFragmentClass(super.getIntent());
474 if (fragmentClass != null) {
475 Header header = new Header();
476 header.fragment = fragmentClass;
477 header.title = getTitle();
478 header.fragmentArguments = getIntent().getExtras();
479 mCurrentHeader = header;
487 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
488 int titleRes, int shortTitleRes) {
489 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
490 titleRes, shortTitleRes);
492 // Some fragments want split ActionBar; these should stay in sync with
493 // uiOptions for fragments also defined as activities in manifest.
494 if (WifiSettings.class.getName().equals(fragmentName) ||
495 WifiP2pSettings.class.getName().equals(fragmentName) ||
496 WifiDisplaySettings.class.getName().equals(fragmentName) ||
497 BluetoothSettings.class.getName().equals(fragmentName) ||
498 DreamSettings.class.getName().equals(fragmentName) ||
499 LocationSettings.class.getName().equals(fragmentName) ||
500 ToggleAccessibilityServicePreferenceFragment.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 SecuritySettingsActivity extends Settings { /* empty */ }
946 public static class LocationSettingsActivity extends Settings { /* empty */ }
947 public static class PrivacySettingsActivity extends Settings { /* empty */ }
948 public static class RunningServicesActivity extends Settings { /* empty */ }
949 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
950 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
951 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
952 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
953 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
954 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
955 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
956 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
957 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
958 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
959 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
960 public static class DreamSettingsActivity extends Settings { /* empty */ }
961 public static class NotificationStationActivity extends Settings { /* empty */ }
962 public static class UserSettingsActivity extends Settings { /* empty */ }
963 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
964 public static class UsbSettingsActivity extends Settings { /* empty */ }
965 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
966 public static class PaymentSettingsActivity extends Settings { /* empty */ }