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