SettingsActivity.java revision e5687b1b32e5c179ce42981119012cc918afa75a
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.settings; 18 19import android.accounts.Account; 20import android.accounts.AccountManager; 21import android.accounts.OnAccountsUpdateListener; 22import android.app.ActionBar; 23import android.app.Activity; 24import android.app.Fragment; 25import android.app.FragmentManager; 26import android.app.FragmentTransaction; 27import android.app.admin.DevicePolicyManager; 28import android.content.BroadcastReceiver; 29import android.content.ComponentName; 30import android.content.Context; 31import android.content.Intent; 32import android.content.IntentFilter; 33import android.content.SharedPreferences; 34import android.content.pm.ActivityInfo; 35import android.content.pm.PackageManager; 36import android.content.pm.PackageManager.NameNotFoundException; 37import android.content.pm.ResolveInfo; 38import android.content.res.Configuration; 39import android.content.res.TypedArray; 40import android.content.res.XmlResourceParser; 41import android.nfc.NfcAdapter; 42import android.os.Bundle; 43import android.os.Handler; 44import android.os.INetworkManagementService; 45import android.os.Message; 46import android.os.RemoteException; 47import android.os.ServiceManager; 48import android.os.UserHandle; 49import android.os.UserManager; 50import android.preference.Preference; 51import android.preference.PreferenceFragment; 52import android.preference.PreferenceManager; 53import android.preference.PreferenceScreen; 54import android.text.TextUtils; 55import android.util.AttributeSet; 56import android.util.Log; 57import android.util.TypedValue; 58import android.util.Xml; 59import android.view.Menu; 60import android.view.MenuInflater; 61import android.view.MenuItem; 62import android.view.View; 63import android.view.View.OnClickListener; 64import android.widget.Button; 65import android.widget.ListView; 66 67import android.widget.SearchView; 68import com.android.internal.util.ArrayUtils; 69import com.android.internal.util.XmlUtils; 70import com.android.settings.accessibility.AccessibilitySettings; 71import com.android.settings.accessibility.CaptionPropertiesFragment; 72import com.android.settings.accounts.AccountSyncSettings; 73import com.android.settings.accounts.AuthenticatorHelper; 74import com.android.settings.accounts.ManageAccountsSettings; 75import com.android.settings.applications.InstalledAppDetails; 76import com.android.settings.applications.ManageApplications; 77import com.android.settings.applications.ProcessStatsUi; 78import com.android.settings.bluetooth.BluetoothSettings; 79import com.android.settings.dashboard.DashboardSummary; 80import com.android.settings.dashboard.Header; 81import com.android.settings.dashboard.HeaderAdapter; 82import com.android.settings.dashboard.NoHomeDialogFragment; 83import com.android.settings.dashboard.SearchResultsSummary; 84import com.android.settings.deviceinfo.Memory; 85import com.android.settings.deviceinfo.UsbSettings; 86import com.android.settings.fuelgauge.PowerUsageSummary; 87import com.android.settings.search.Index; 88import com.android.settings.inputmethod.InputMethodAndLanguageSettings; 89import com.android.settings.inputmethod.KeyboardLayoutPickerFragment; 90import com.android.settings.inputmethod.SpellCheckersSettings; 91import com.android.settings.inputmethod.UserDictionaryList; 92import com.android.settings.location.LocationSettings; 93import com.android.settings.nfc.AndroidBeam; 94import com.android.settings.nfc.PaymentSettings; 95import com.android.settings.print.PrintJobSettingsFragment; 96import com.android.settings.print.PrintSettingsFragment; 97import com.android.settings.tts.TextToSpeechSettings; 98import com.android.settings.users.UserSettings; 99import com.android.settings.vpn2.VpnSettings; 100import com.android.settings.wfd.WifiDisplaySettings; 101import com.android.settings.wifi.AdvancedWifiSettings; 102import com.android.settings.wifi.WifiSettings; 103import com.android.settings.wifi.p2p.WifiP2pSettings; 104import org.xmlpull.v1.XmlPullParser; 105import org.xmlpull.v1.XmlPullParserException; 106 107import java.io.IOException; 108import java.util.ArrayList; 109import java.util.Collections; 110import java.util.Comparator; 111import java.util.HashMap; 112import java.util.List; 113 114import static com.android.settings.dashboard.Header.HEADER_ID_UNDEFINED; 115 116public class SettingsActivity extends Activity 117 implements PreferenceManager.OnPreferenceTreeClickListener, 118 PreferenceFragment.OnPreferenceStartFragmentCallback, 119 ButtonBarHandler, OnAccountsUpdateListener, FragmentManager.OnBackStackChangedListener, 120 SearchView.OnQueryTextListener, SearchView.OnCloseListener, 121 MenuItem.OnActionExpandListener { 122 123 private static final String LOG_TAG = "Settings"; 124 125 // Constants for state save/restore 126 private static final String SAVE_KEY_HEADERS = ":settings:headers"; 127 private static final String SAVE_KEY_SEARCH_MENU_EXPANDED = ":settings:search_menu_expanded"; 128 private static final String SAVE_KEY_SEARCH_QUERY = ":settings:search_query"; 129 private static final String SAVE_KEY_SHOW_HOME_AS_UP = ":settings:show_home_as_up"; 130 131 /** 132 * When starting this activity, the invoking Intent can contain this extra 133 * string to specify which fragment should be initially displayed. 134 * <p/>Starting from Key Lime Pie, when this argument is passed in, the activity 135 * will call isValidFragment() to confirm that the fragment class name is valid for this 136 * activity. 137 */ 138 public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment"; 139 140 /** 141 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, 142 * this extra can also be specified to supply a Bundle of arguments to pass 143 * to that fragment when it is instantiated during the initial creation 144 * of the activity. 145 */ 146 public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"; 147 148 /** 149 * Fragment "key" argument passed thru {@link #EXTRA_SHOW_FRAGMENT_ARGUMENTS} 150 */ 151 public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; 152 153 /** 154 * When starting this activity, the invoking Intent can contain this extra 155 * boolean that the header list should not be displayed. This is most often 156 * used in conjunction with {@link #EXTRA_SHOW_FRAGMENT} to launch 157 * the activity to display a specific fragment that the user has navigated 158 * to. 159 */ 160 public static final String EXTRA_NO_HEADERS = ":settings:no_headers"; 161 162 public static final String BACK_STACK_PREFS = ":settings:prefs"; 163 164 // extras that allow any preference activity to be launched as part of a wizard 165 166 // show Back and Next buttons? takes boolean parameter 167 // Back will then return RESULT_CANCELED and Next RESULT_OK 168 protected static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar"; 169 170 // add a Skip button? 171 private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip"; 172 173 // specify custom text for the Back or Next buttons, or cause a button to not appear 174 // at all by setting it to null 175 protected static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text"; 176 protected static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text"; 177 178 /** 179 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, 180 * this extra can also be specify to supply the title to be shown for 181 * that fragment. 182 */ 183 public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":settings:show_fragment_title"; 184 185 private static final String META_DATA_KEY_FRAGMENT_CLASS = 186 "com.android.settings.FRAGMENT_CLASS"; 187 188 private static final String EXTRA_UI_OPTIONS = "settings:ui_options"; 189 190 private static final String EMPTY_QUERY = ""; 191 192 private static boolean sShowNoHomeNotice = false; 193 194 private String mFragmentClass; 195 private Header mSelectedHeader; 196 197 private CharSequence mInitialTitle; 198 199 // Show only these settings for restricted users 200 private int[] SETTINGS_FOR_RESTRICTED = { 201 R.id.wireless_section, 202 R.id.wifi_settings, 203 R.id.bluetooth_settings, 204 R.id.data_usage_settings, 205 R.id.wireless_settings, 206 R.id.device_section, 207 R.id.sound_settings, 208 R.id.display_settings, 209 R.id.storage_settings, 210 R.id.application_settings, 211 R.id.battery_settings, 212 R.id.personal_section, 213 R.id.location_settings, 214 R.id.security_settings, 215 R.id.language_settings, 216 R.id.user_settings, 217 R.id.account_settings, 218 R.id.account_add, 219 R.id.system_section, 220 R.id.date_time_settings, 221 R.id.about_settings, 222 R.id.accessibility_settings, 223 R.id.print_settings, 224 R.id.nfc_payment_settings, 225 R.id.home_settings, 226 R.id.dashboard 227 }; 228 229 private static final String[] ENTRY_FRAGMENTS = { 230 WirelessSettings.class.getName(), 231 WifiSettings.class.getName(), 232 AdvancedWifiSettings.class.getName(), 233 BluetoothSettings.class.getName(), 234 TetherSettings.class.getName(), 235 WifiP2pSettings.class.getName(), 236 VpnSettings.class.getName(), 237 DateTimeSettings.class.getName(), 238 LocalePicker.class.getName(), 239 InputMethodAndLanguageSettings.class.getName(), 240 SpellCheckersSettings.class.getName(), 241 UserDictionaryList.class.getName(), 242 UserDictionarySettings.class.getName(), 243 SoundSettings.class.getName(), 244 DisplaySettings.class.getName(), 245 DeviceInfoSettings.class.getName(), 246 ManageApplications.class.getName(), 247 ProcessStatsUi.class.getName(), 248 NotificationStation.class.getName(), 249 LocationSettings.class.getName(), 250 SecuritySettings.class.getName(), 251 PrivacySettings.class.getName(), 252 DeviceAdminSettings.class.getName(), 253 AccessibilitySettings.class.getName(), 254 CaptionPropertiesFragment.class.getName(), 255 com.android.settings.accessibility.ToggleInversionPreferenceFragment.class.getName(), 256 com.android.settings.accessibility.ToggleContrastPreferenceFragment.class.getName(), 257 com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(), 258 TextToSpeechSettings.class.getName(), 259 Memory.class.getName(), 260 DevelopmentSettings.class.getName(), 261 UsbSettings.class.getName(), 262 AndroidBeam.class.getName(), 263 WifiDisplaySettings.class.getName(), 264 PowerUsageSummary.class.getName(), 265 AccountSyncSettings.class.getName(), 266 CryptKeeperSettings.class.getName(), 267 DataUsageSummary.class.getName(), 268 DreamSettings.class.getName(), 269 UserSettings.class.getName(), 270 NotificationAccessSettings.class.getName(), 271 ManageAccountsSettings.class.getName(), 272 PrintSettingsFragment.class.getName(), 273 PrintJobSettingsFragment.class.getName(), 274 TrustedCredentialsSettings.class.getName(), 275 PaymentSettings.class.getName(), 276 KeyboardLayoutPickerFragment.class.getName(), 277 ZenModeSettings.class.getName(), 278 NotificationSettings.class.getName(), 279 ChooseLockPassword.ChooseLockPasswordFragment.class.getName(), 280 ChooseLockPattern.ChooseLockPatternFragment.class.getName(), 281 InstalledAppDetails.class.getName() 282 }; 283 284 private SharedPreferences mDevelopmentPreferences; 285 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener; 286 287 private AuthenticatorHelper mAuthenticatorHelper; 288 private boolean mListeningToAccountUpdates; 289 290 private boolean mBatteryPresent = true; 291 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() { 292 293 @Override 294 public void onReceive(Context context, Intent intent) { 295 String action = intent.getAction(); 296 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 297 boolean batteryPresent = Utils.isBatteryPresent(intent); 298 299 if (mBatteryPresent != batteryPresent) { 300 mBatteryPresent = batteryPresent; 301 invalidateHeaders(); 302 } 303 } 304 } 305 }; 306 307 private Button mNextButton; 308 private ActionBar mActionBar; 309 private boolean mDisplayHomeAsUpEnabled; 310 311 private SearchView mSearchView; 312 private MenuItem mSearchMenuItem; 313 private boolean mSearchMenuItemExpanded = false; 314 private SearchResultsSummary mSearchResultsFragment; 315 private String mSearchQuery; 316 317 // Headers 318 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>(); 319 private final ArrayList<Header> mHeaders = new ArrayList<Header>(); 320 private HeaderAdapter mHeaderAdapter; 321 322 private static final int MSG_BUILD_HEADERS = 1; 323 private Handler mHandler = new Handler() { 324 @Override 325 public void handleMessage(Message msg) { 326 switch (msg.what) { 327 case MSG_BUILD_HEADERS: { 328 mHeaders.clear(); 329 onBuildHeaders(mHeaders); 330 mHeaderAdapter.notifyDataSetChanged(); 331 } break; 332 } 333 } 334 }; 335 336 private boolean mNeedToRevertToInitialFragment = false; 337 338 @Override 339 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) { 340 // Override the fragment title for Wallpaper settings 341 int titleRes = pref.getTitleRes(); 342 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) { 343 titleRes = R.string.wallpaper_settings_fragment_title; 344 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName()) 345 && UserHandle.myUserId() != UserHandle.USER_OWNER) { 346 if (UserManager.get(this).isLinkedUser()) { 347 titleRes = R.string.profile_info_settings_title; 348 } else { 349 titleRes = R.string.user_info_settings_title; 350 } 351 } 352 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(), 353 null, 0); 354 return true; 355 } 356 357 @Override 358 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 359 return false; 360 } 361 362 private void invalidateHeaders() { 363 if (!mHandler.hasMessages(MSG_BUILD_HEADERS)) { 364 mHandler.sendEmptyMessage(MSG_BUILD_HEADERS); 365 } 366 } 367 368 @Override 369 public void onConfigurationChanged(Configuration newConfig) { 370 super.onConfigurationChanged(newConfig); 371 Index.getInstance(this).update(); 372 } 373 374 @Override 375 protected void onStart() { 376 super.onStart(); 377 378 if (mNeedToRevertToInitialFragment) { 379 revertToInitialFragment(); 380 } 381 } 382 383 @Override 384 public boolean onCreateOptionsMenu(Menu menu) { 385 MenuInflater inflater = getMenuInflater(); 386 inflater.inflate(R.menu.options_menu, menu); 387 388 // Cache the search query (can be overriden by the OnQueryTextListener) 389 final String query = mSearchQuery; 390 391 mSearchMenuItem = menu.findItem(R.id.search); 392 mSearchView = (SearchView) mSearchMenuItem.getActionView(); 393 394 mSearchMenuItem.setOnActionExpandListener(this); 395 mSearchView.setOnQueryTextListener(this); 396 mSearchView.setOnCloseListener(this); 397 398 if (mSearchMenuItemExpanded) { 399 mSearchMenuItem.expandActionView(); 400 } 401 mSearchView.setQuery(query, true /* submit */); 402 403 return true; 404 } 405 406 @Override 407 protected void onCreate(Bundle savedState) { 408 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) { 409 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0)); 410 } 411 412 Index.getInstance(this).update(); 413 414 mAuthenticatorHelper = new AuthenticatorHelper(); 415 mAuthenticatorHelper.updateAuthDescriptions(this); 416 mAuthenticatorHelper.onAccountsUpdated(this, null); 417 418 DevicePolicyManager dpm = 419 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 420 421 mHeaderAdapter = new HeaderAdapter(this, mHeaders, mAuthenticatorHelper, dpm); 422 423 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE, 424 Context.MODE_PRIVATE); 425 426 getMetaData(); 427 428 super.onCreate(savedState); 429 430 setContentView(R.layout.settings_main); 431 432 getFragmentManager().addOnBackStackChangedListener(this); 433 434 mDisplayHomeAsUpEnabled = true; 435 436 String initialFragmentName = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT); 437 Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); 438 439 if (savedState != null) { 440 // We are restarting from a previous saved state; used that to initialize, instead 441 // of starting fresh. 442 mSearchMenuItemExpanded = savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED); 443 mSearchQuery = savedState.getString(SAVE_KEY_SEARCH_QUERY); 444 445 final String initialTitle = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT_TITLE); 446 mInitialTitle = (initialTitle != null) ? initialTitle : getTitle(); 447 setTitle(mInitialTitle); 448 449 ArrayList<Header> headers = savedState.getParcelableArrayList(SAVE_KEY_HEADERS); 450 if (headers != null) { 451 mHeaders.addAll(headers); 452 setTitleFromBackStack(); 453 } 454 455 mDisplayHomeAsUpEnabled = savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP); 456 } else { 457 // We need to build the Headers in all cases 458 onBuildHeaders(mHeaders); 459 460 if (initialFragmentName != null) { 461 final ComponentName cn = getIntent().getComponent(); 462 // No UP is we are launched thru a Settings shortcut 463 if (!cn.getClassName().equals(SubSettings.class.getName())) { 464 mDisplayHomeAsUpEnabled = false; 465 } 466 final String initialTitle = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT_TITLE); 467 mInitialTitle = (initialTitle != null) ? initialTitle : getTitle(); 468 setTitle(mInitialTitle); 469 470 switchToFragment( initialFragmentName, initialArguments, true, false, 471 mInitialTitle, false); 472 } else { 473 // No UP if we are displaying the Headers 474 mDisplayHomeAsUpEnabled = false; 475 if (mHeaders.size() > 0) { 476 mInitialTitle = getText(R.string.dashboard_title); 477 switchToFragment(DashboardSummary.class.getName(), null, false, false, 478 mInitialTitle, false); 479 } 480 } 481 } 482 483 mActionBar = getActionBar(); 484 mActionBar.setHomeButtonEnabled(true); 485 mActionBar.setDisplayHomeAsUpEnabled(mDisplayHomeAsUpEnabled); 486 487 // see if we should show Back/Next buttons 488 Intent intent = getIntent(); 489 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) { 490 491 View buttonBar = findViewById(com.android.internal.R.id.button_bar); 492 if (buttonBar != null) { 493 buttonBar.setVisibility(View.VISIBLE); 494 495 Button backButton = (Button)findViewById(com.android.internal.R.id.back_button); 496 backButton.setOnClickListener(new OnClickListener() { 497 public void onClick(View v) { 498 setResult(RESULT_CANCELED); 499 finish(); 500 } 501 }); 502 Button skipButton = (Button)findViewById(com.android.internal.R.id.skip_button); 503 skipButton.setOnClickListener(new OnClickListener() { 504 public void onClick(View v) { 505 setResult(RESULT_OK); 506 finish(); 507 } 508 }); 509 mNextButton = (Button)findViewById(com.android.internal.R.id.next_button); 510 mNextButton.setOnClickListener(new OnClickListener() { 511 public void onClick(View v) { 512 setResult(RESULT_OK); 513 finish(); 514 } 515 }); 516 517 // set our various button parameters 518 if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) { 519 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT); 520 if (TextUtils.isEmpty(buttonText)) { 521 mNextButton.setVisibility(View.GONE); 522 } 523 else { 524 mNextButton.setText(buttonText); 525 } 526 } 527 if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) { 528 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT); 529 if (TextUtils.isEmpty(buttonText)) { 530 backButton.setVisibility(View.GONE); 531 } 532 else { 533 backButton.setText(buttonText); 534 } 535 } 536 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) { 537 skipButton.setVisibility(View.VISIBLE); 538 } 539 } 540 } 541 } 542 543 @Override 544 public void onBackStackChanged() { 545 setTitleFromBackStack(); 546 } 547 548 private int setTitleFromBackStack() { 549 final int count = getFragmentManager().getBackStackEntryCount(); 550 551 if (count == 0) { 552 setTitle(mInitialTitle); 553 return 0; 554 } 555 556 FragmentManager.BackStackEntry bse = getFragmentManager().getBackStackEntryAt(count - 1); 557 setTitleFromBackStackEntry(bse); 558 559 return count; 560 } 561 562 private void setTitleFromBackStackEntry(FragmentManager.BackStackEntry bse) { 563 final CharSequence title; 564 final int titleRes = bse.getBreadCrumbTitleRes(); 565 if (titleRes > 0) { 566 title = getText(titleRes); 567 } else { 568 title = bse.getBreadCrumbTitle(); 569 } 570 if (title != null) { 571 setTitle(title); 572 } 573 } 574 575 @Override 576 protected void onSaveInstanceState(Bundle outState) { 577 super.onSaveInstanceState(outState); 578 579 if (mHeaders.size() > 0) { 580 outState.putParcelableArrayList(SAVE_KEY_HEADERS, mHeaders); 581 } 582 583 outState.putBoolean(SAVE_KEY_SHOW_HOME_AS_UP, mDisplayHomeAsUpEnabled); 584 585 // The option menus are created if the ActionBar is visible and they are also created 586 // asynchronously. If you launch Settings with an Intent action like 587 // android.intent.action.POWER_USAGE_SUMMARY and at the same time your device is locked 588 // thru a LockScreen, onCreateOptionsMenu() is not yet called and references to the search 589 // menu item and search view are null. 590 boolean isExpanded = (mSearchMenuItem != null) && mSearchMenuItem.isActionViewExpanded(); 591 outState.putBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED, isExpanded); 592 593 String query = (mSearchView != null) ? mSearchView.getQuery().toString() : EMPTY_QUERY; 594 outState.putString(SAVE_KEY_SEARCH_QUERY, query); 595 } 596 597 @Override 598 public void onResume() { 599 super.onResume(); 600 601 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() { 602 @Override 603 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 604 invalidateHeaders(); 605 } 606 }; 607 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener( 608 mDevelopmentPreferencesListener); 609 610 mHeaderAdapter.resume(this); 611 invalidateHeaders(); 612 613 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 614 } 615 616 @Override 617 public void onPause() { 618 super.onPause(); 619 620 unregisterReceiver(mBatteryInfoReceiver); 621 622 mHeaderAdapter.pause(); 623 624 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener( 625 mDevelopmentPreferencesListener); 626 627 mDevelopmentPreferencesListener = null; 628 } 629 630 @Override 631 public void onDestroy() { 632 super.onDestroy(); 633 if (mListeningToAccountUpdates) { 634 AccountManager.get(this).removeOnAccountsUpdatedListener(this); 635 } 636 } 637 638 protected boolean isValidFragment(String fragmentName) { 639 // Almost all fragments are wrapped in this, 640 // except for a few that have their own activities. 641 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) { 642 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true; 643 } 644 return false; 645 } 646 647 /** 648 * When in two-pane mode, switch to the fragment pane to show the given 649 * preference fragment. 650 * 651 * @param header The new header to display. 652 * @param position The position of the Header in the list. 653 */ 654 private void onHeaderClick(Header header, int position) { 655 if (header == null) { 656 return; 657 } 658 if (header.fragment != null) { 659 startWithFragment(header.fragment, header.fragmentArguments, null, 0, 660 header.getTitle(getResources())); 661 } else if (header.intent != null) { 662 startActivity(header.intent); 663 } 664 } 665 666 /** 667 * Called to determine whether the header list should be hidden. 668 * The default implementation returns the 669 * value given in {@link #EXTRA_NO_HEADERS} or false if it is not supplied. 670 * This is set to false, for example, when the activity is being re-launched 671 * to show a particular preference activity. 672 */ 673 public boolean onIsHidingHeaders() { 674 return getIntent().getBooleanExtra(EXTRA_NO_HEADERS, false); 675 } 676 677 @Override 678 public Intent getIntent() { 679 Intent superIntent = super.getIntent(); 680 String startingFragment = getStartingFragmentClass(superIntent); 681 // This is called from super.onCreate, isMultiPane() is not yet reliable 682 // Do not use onIsHidingHeaders either, which relies itself on this method 683 if (startingFragment != null) { 684 Intent modIntent = new Intent(superIntent); 685 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment); 686 Bundle args = superIntent.getExtras(); 687 if (args != null) { 688 args = new Bundle(args); 689 } else { 690 args = new Bundle(); 691 } 692 args.putParcelable("intent", superIntent); 693 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras()); 694 return modIntent; 695 } 696 return superIntent; 697 } 698 699 /** 700 * Checks if the component name in the intent is different from the Settings class and 701 * returns the class name to load as a fragment. 702 */ 703 private String getStartingFragmentClass(Intent intent) { 704 if (mFragmentClass != null) return mFragmentClass; 705 706 String intentClass = intent.getComponent().getClassName(); 707 if (intentClass.equals(getClass().getName())) return null; 708 709 if ("com.android.settings.ManageApplications".equals(intentClass) 710 || "com.android.settings.RunningServices".equals(intentClass) 711 || "com.android.settings.applications.StorageUse".equals(intentClass)) { 712 // Old names of manage apps. 713 intentClass = com.android.settings.applications.ManageApplications.class.getName(); 714 } 715 716 return intentClass; 717 } 718 719 /** 720 * Start a new fragment containing a preference panel. If the preferences 721 * are being displayed in multi-pane mode, the given fragment class will 722 * be instantiated and placed in the appropriate pane. If running in 723 * single-pane mode, a new activity will be launched in which to show the 724 * fragment. 725 * 726 * @param fragmentClass Full name of the class implementing the fragment. 727 * @param args Any desired arguments to supply to the fragment. 728 * @param titleRes Optional resource identifier of the title of this 729 * fragment. 730 * @param titleText Optional text of the title of this fragment. 731 * @param resultTo Optional fragment that result data should be sent to. 732 * If non-null, resultTo.onActivityResult() will be called when this 733 * preference panel is done. The launched panel must use 734 * {@link #finishPreferencePanel(Fragment, int, Intent)} when done. 735 * @param resultRequestCode If resultTo is non-null, this is the caller's 736 * request code to be received with the resut. 737 */ 738 public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes, 739 CharSequence titleText, Fragment resultTo, int resultRequestCode) { 740 String title; 741 if (titleRes > 0) { 742 title = getString(titleRes); 743 } else { 744 title = titleText.toString(); 745 } 746 startWithFragment(fragmentClass, args, resultTo, resultRequestCode, title); 747 } 748 749 /** 750 * Called by a preference panel fragment to finish itself. 751 * 752 * @param caller The fragment that is asking to be finished. 753 * @param resultCode Optional result code to send back to the original 754 * launching fragment. 755 * @param resultData Optional result data to send back to the original 756 * launching fragment. 757 */ 758 public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) { 759 setResult(resultCode, resultData); 760 } 761 762 /** 763 * Start a new fragment. 764 * 765 * @param fragment The fragment to start 766 * @param push If true, the current fragment will be pushed onto the back stack. If false, 767 * the current fragment will be replaced. 768 */ 769 public void startPreferenceFragment(Fragment fragment, boolean push) { 770 FragmentTransaction transaction = getFragmentManager().beginTransaction(); 771 transaction.replace(R.id.prefs, fragment); 772 if (push) { 773 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 774 transaction.addToBackStack(BACK_STACK_PREFS); 775 } else { 776 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); 777 } 778 transaction.commitAllowingStateLoss(); 779 } 780 781 /** 782 * Switch to a specific Fragment with taking care of validation, Title and BackStack 783 */ 784 private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate, 785 boolean addToBackStack, CharSequence title, boolean withTransition) { 786 if (validate && !isValidFragment(fragmentName)) { 787 throw new IllegalArgumentException("Invalid fragment for this activity: " 788 + fragmentName); 789 } 790 Fragment f = Fragment.instantiate(this, fragmentName, args); 791 FragmentTransaction transaction = getFragmentManager().beginTransaction(); 792 transaction.replace(R.id.prefs, f); 793 if (withTransition) { 794 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); 795 } 796 if (addToBackStack) { 797 transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS); 798 } 799 if (title != null) { 800 transaction.setBreadCrumbTitle(title); 801 } 802 transaction.commitAllowingStateLoss(); 803 return f; 804 } 805 806 /** 807 * Start a new instance of this activity, showing only the given fragment. 808 * When launched in this mode, the given preference fragment will be instantiated and fill the 809 * entire activity. 810 * 811 * @param fragmentName The name of the fragment to display. 812 * @param args Optional arguments to supply to the fragment. 813 * @param resultTo Option fragment that should receive the result of 814 * the activity launch. 815 * @param resultRequestCode If resultTo is non-null, this is the request 816 * code in which to report the result. 817 * @param title String to display for the title of this set of preferences. 818 */ 819 public void startWithFragment(String fragmentName, Bundle args, 820 Fragment resultTo, int resultRequestCode, CharSequence title) { 821 Intent intent = onBuildStartFragmentIntent(fragmentName, args, title); 822 if (resultTo == null) { 823 startActivity(intent); 824 } else { 825 resultTo.startActivityForResult(intent, resultRequestCode); 826 } 827 } 828 829 /** 830 * Build an Intent to launch a new activity showing the selected fragment. 831 * The implementation constructs an Intent that re-launches the current activity with the 832 * appropriate arguments to display the fragment. 833 * 834 * @param fragmentName The name of the fragment to display. 835 * @param args Optional arguments to supply to the fragment. 836 * @param title Optional title to show for this item. 837 * @return Returns an Intent that can be launched to display the given 838 * fragment. 839 */ 840 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args, CharSequence title) { 841 Intent intent = new Intent(Intent.ACTION_MAIN); 842 intent.setClass(this, SubSettings.class); 843 intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName); 844 intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); 845 intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, title); 846 intent.putExtra(EXTRA_NO_HEADERS, true); 847 return intent; 848 } 849 850 /** 851 * Called when the activity needs its list of headers build. 852 * 853 * @param headers The list in which to place the headers. 854 */ 855 private void onBuildHeaders(List<Header> headers) { 856 loadHeadersFromResource(R.xml.settings_headers, headers); 857 updateHeaderList(headers); 858 } 859 860 /** 861 * Parse the given XML file as a header description, adding each 862 * parsed Header into the target list. 863 * 864 * @param resid The XML resource to load and parse. 865 * @param target The list in which the parsed headers should be placed. 866 */ 867 private void loadHeadersFromResource(int resid, List<Header> target) { 868 XmlResourceParser parser = null; 869 try { 870 parser = getResources().getXml(resid); 871 AttributeSet attrs = Xml.asAttributeSet(parser); 872 873 int type; 874 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 875 && type != XmlPullParser.START_TAG) { 876 // Parse next until start tag is found 877 } 878 879 String nodeName = parser.getName(); 880 if (!"preference-headers".equals(nodeName)) { 881 throw new RuntimeException( 882 "XML document must start with <preference-headers> tag; found" 883 + nodeName + " at " + parser.getPositionDescription()); 884 } 885 886 Bundle curBundle = null; 887 888 final int outerDepth = parser.getDepth(); 889 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 890 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 891 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 892 continue; 893 } 894 895 nodeName = parser.getName(); 896 if ("header".equals(nodeName)) { 897 Header header = new Header(); 898 899 TypedArray sa = obtainStyledAttributes( 900 attrs, com.android.internal.R.styleable.PreferenceHeader); 901 header.id = sa.getResourceId( 902 com.android.internal.R.styleable.PreferenceHeader_id, 903 (int)HEADER_ID_UNDEFINED); 904 TypedValue tv = sa.peekValue( 905 com.android.internal.R.styleable.PreferenceHeader_title); 906 if (tv != null && tv.type == TypedValue.TYPE_STRING) { 907 if (tv.resourceId != 0) { 908 header.titleRes = tv.resourceId; 909 } else { 910 header.title = tv.string; 911 } 912 } 913 tv = sa.peekValue( 914 com.android.internal.R.styleable.PreferenceHeader_summary); 915 if (tv != null && tv.type == TypedValue.TYPE_STRING) { 916 if (tv.resourceId != 0) { 917 header.summaryRes = tv.resourceId; 918 } else { 919 header.summary = tv.string; 920 } 921 } 922 header.iconRes = sa.getResourceId( 923 com.android.internal.R.styleable.PreferenceHeader_icon, 0); 924 header.fragment = sa.getString( 925 com.android.internal.R.styleable.PreferenceHeader_fragment); 926 sa.recycle(); 927 928 if (curBundle == null) { 929 curBundle = new Bundle(); 930 } 931 932 final int innerDepth = parser.getDepth(); 933 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 934 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 935 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 936 continue; 937 } 938 939 String innerNodeName = parser.getName(); 940 if (innerNodeName.equals("extra")) { 941 getResources().parseBundleExtra("extra", attrs, curBundle); 942 XmlUtils.skipCurrentTag(parser); 943 944 } else if (innerNodeName.equals("intent")) { 945 header.intent = Intent.parseIntent(getResources(), parser, attrs); 946 947 } else { 948 XmlUtils.skipCurrentTag(parser); 949 } 950 } 951 952 if (curBundle.size() > 0) { 953 header.fragmentArguments = curBundle; 954 curBundle = null; 955 } 956 957 target.add(header); 958 } else { 959 XmlUtils.skipCurrentTag(parser); 960 } 961 } 962 963 } catch (XmlPullParserException e) { 964 throw new RuntimeException("Error parsing headers", e); 965 } catch (IOException e) { 966 throw new RuntimeException("Error parsing headers", e); 967 } finally { 968 if (parser != null) parser.close(); 969 } 970 } 971 972 private void updateHeaderList(List<Header> target) { 973 final boolean showDev = mDevelopmentPreferences.getBoolean( 974 DevelopmentSettings.PREF_SHOW, 975 android.os.Build.TYPE.equals("eng")); 976 int i = 0; 977 978 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); 979 mHeaderIndexMap.clear(); 980 while (i < target.size()) { 981 Header header = target.get(i); 982 // Ids are integers, so downcasting 983 int id = (int) header.id; 984 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) { 985 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header); 986 } else if (id == R.id.wifi_settings) { 987 // Remove WiFi Settings if WiFi service is not available. 988 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) { 989 target.remove(i); 990 } 991 } else if (id == R.id.bluetooth_settings) { 992 // Remove Bluetooth Settings if Bluetooth service is not available. 993 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) { 994 target.remove(i); 995 } 996 } else if (id == R.id.data_usage_settings) { 997 // Remove data usage when kernel module not enabled 998 final INetworkManagementService netManager = INetworkManagementService.Stub 999 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); 1000 try { 1001 if (!netManager.isBandwidthControlEnabled()) { 1002 target.remove(i); 1003 } 1004 } catch (RemoteException e) { 1005 // ignored 1006 } 1007 } else if (id == R.id.battery_settings) { 1008 // Remove battery settings when battery is not available. (e.g. TV) 1009 1010 if (!mBatteryPresent) { 1011 target.remove(i); 1012 } 1013 } else if (id == R.id.account_settings) { 1014 int headerIndex = i + 1; 1015 i = insertAccountsHeaders(target, headerIndex); 1016 } else if (id == R.id.home_settings) { 1017 if (!updateHomeSettingHeaders(header)) { 1018 target.remove(i); 1019 } 1020 } else if (id == R.id.user_settings) { 1021 if (!UserHandle.MU_ENABLED 1022 || !UserManager.supportsMultipleUsers() 1023 || Utils.isMonkeyRunning()) { 1024 target.remove(i); 1025 } 1026 } else if (id == R.id.nfc_payment_settings) { 1027 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) { 1028 target.remove(i); 1029 } else { 1030 // Only show if NFC is on and we have the HCE feature 1031 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this); 1032 if (!adapter.isEnabled() || !getPackageManager().hasSystemFeature( 1033 PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) { 1034 target.remove(i); 1035 } 1036 } 1037 } else if (id == R.id.development_settings) { 1038 if (!showDev) { 1039 target.remove(i); 1040 } 1041 } else if (id == R.id.account_add) { 1042 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) { 1043 target.remove(i); 1044 } 1045 } 1046 1047 if (i < target.size() && target.get(i) == header 1048 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0 1049 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) { 1050 target.remove(i); 1051 } 1052 1053 // Increment if the current one wasn't removed by the Utils code. 1054 if (i < target.size() && target.get(i) == header) { 1055 mHeaderIndexMap.put(id, i); 1056 i++; 1057 } 1058 } 1059 } 1060 1061 private int insertAccountsHeaders(List<Header> target, int headerIndex) { 1062 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes(); 1063 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length); 1064 for (String accountType : accountTypes) { 1065 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType); 1066 if (label == null) { 1067 continue; 1068 } 1069 1070 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType); 1071 boolean skipToAccount = accounts.length == 1 1072 && !mAuthenticatorHelper.hasAccountPreferences(accountType); 1073 Header accHeader = new Header(); 1074 accHeader.title = label; 1075 if (accHeader.extras == null) { 1076 accHeader.extras = new Bundle(); 1077 } 1078 if (skipToAccount) { 1079 accHeader.fragment = AccountSyncSettings.class.getName(); 1080 accHeader.fragmentArguments = new Bundle(); 1081 // Need this for the icon 1082 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType); 1083 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]); 1084 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY, 1085 accounts[0]); 1086 } else { 1087 accHeader.fragment = ManageAccountsSettings.class.getName(); 1088 accHeader.fragmentArguments = new Bundle(); 1089 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType); 1090 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, 1091 accountType); 1092 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL, 1093 label.toString()); 1094 } 1095 accountHeaders.add(accHeader); 1096 mAuthenticatorHelper.preloadDrawableForType(this, accountType); 1097 } 1098 1099 // Sort by label 1100 Collections.sort(accountHeaders, new Comparator<Header>() { 1101 @Override 1102 public int compare(Header h1, Header h2) { 1103 return h1.title.toString().compareTo(h2.title.toString()); 1104 } 1105 }); 1106 1107 for (Header header : accountHeaders) { 1108 target.add(headerIndex++, header); 1109 } 1110 if (!mListeningToAccountUpdates) { 1111 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true); 1112 mListeningToAccountUpdates = true; 1113 } 1114 return headerIndex; 1115 } 1116 1117 private boolean updateHomeSettingHeaders(Header header) { 1118 // Once we decide to show Home settings, keep showing it forever 1119 SharedPreferences sp = getSharedPreferences(HomeSettings.HOME_PREFS, Context.MODE_PRIVATE); 1120 if (sp.getBoolean(HomeSettings.HOME_PREFS_DO_SHOW, false)) { 1121 return true; 1122 } 1123 1124 try { 1125 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>(); 1126 getPackageManager().getHomeActivities(homeApps); 1127 if (homeApps.size() < 2) { 1128 // When there's only one available home app, omit this settings 1129 // category entirely at the top level UI. If the user just 1130 // uninstalled the penultimate home app candidiate, we also 1131 // now tell them about why they aren't seeing 'Home' in the list. 1132 if (sShowNoHomeNotice) { 1133 sShowNoHomeNotice = false; 1134 NoHomeDialogFragment.show(this); 1135 } 1136 return false; 1137 } else { 1138 // Okay, we're allowing the Home settings category. Tell it, when 1139 // invoked via this front door, that we'll need to be told about the 1140 // case when the user uninstalls all but one home app. 1141 if (header.fragmentArguments == null) { 1142 header.fragmentArguments = new Bundle(); 1143 } 1144 header.fragmentArguments.putBoolean(HomeSettings.HOME_SHOW_NOTICE, true); 1145 } 1146 } catch (Exception e) { 1147 // Can't look up the home activity; bail on configuring the icon 1148 Log.w(LOG_TAG, "Problem looking up home activity!", e); 1149 } 1150 1151 sp.edit().putBoolean(HomeSettings.HOME_PREFS_DO_SHOW, true).apply(); 1152 return true; 1153 } 1154 1155 private void getMetaData() { 1156 try { 1157 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(), 1158 PackageManager.GET_META_DATA); 1159 if (ai == null || ai.metaData == null) return; 1160 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS); 1161 } catch (NameNotFoundException nnfe) { 1162 // No recovery 1163 Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString()); 1164 } 1165 } 1166 1167 // give subclasses access to the Next button 1168 public boolean hasNextButton() { 1169 return mNextButton != null; 1170 } 1171 1172 public Button getNextButton() { 1173 return mNextButton; 1174 } 1175 1176 public HeaderAdapter getHeaderAdapter() { 1177 return mHeaderAdapter; 1178 } 1179 1180 public void onListItemClick(ListView l, View v, int position, long id) { 1181 if (!isResumed()) { 1182 return; 1183 } 1184 Object item = mHeaderAdapter.getItem(position); 1185 if (item instanceof Header) { 1186 mSelectedHeader = (Header) item; 1187 onHeaderClick(mSelectedHeader, position); 1188 revertToInitialFragment(); 1189 } 1190 } 1191 1192 @Override 1193 public boolean shouldUpRecreateTask(Intent targetIntent) { 1194 return super.shouldUpRecreateTask(new Intent(this, SettingsActivity.class)); 1195 } 1196 1197 @Override 1198 public void onAccountsUpdated(Account[] accounts) { 1199 // TODO: watch for package upgrades to invalidate cache; see 7206643 1200 mAuthenticatorHelper.updateAuthDescriptions(this); 1201 mAuthenticatorHelper.onAccountsUpdated(this, accounts); 1202 invalidateHeaders(); 1203 } 1204 1205 public static void requestHomeNotice() { 1206 sShowNoHomeNotice = true; 1207 } 1208 1209 @Override 1210 public boolean onQueryTextSubmit(String query) { 1211 switchToSearchResultsFragmentIfNeeded(); 1212 mSearchQuery = query; 1213 return mSearchResultsFragment.onQueryTextSubmit(query); 1214 } 1215 1216 @Override 1217 public boolean onQueryTextChange(String newText) { 1218 mSearchQuery = newText; 1219 return false; 1220 } 1221 1222 @Override 1223 public boolean onClose() { 1224 return false; 1225 } 1226 1227 @Override 1228 public boolean onMenuItemActionExpand(MenuItem item) { 1229 if (item.getItemId() == mSearchMenuItem.getItemId()) { 1230 switchToSearchResultsFragmentIfNeeded(); 1231 } 1232 return true; 1233 } 1234 1235 @Override 1236 public boolean onMenuItemActionCollapse(MenuItem item) { 1237 if (item.getItemId() == mSearchMenuItem.getItemId()) { 1238 if (mSearchMenuItemExpanded) { 1239 revertToInitialFragment(); 1240 } 1241 } 1242 return true; 1243 } 1244 1245 private void switchToSearchResultsFragmentIfNeeded() { 1246 if (mSearchResultsFragment != null) { 1247 return; 1248 } 1249 Fragment current = getFragmentManager().findFragmentById(R.id.prefs); 1250 if (current != null && current instanceof SearchResultsSummary) { 1251 mSearchResultsFragment = (SearchResultsSummary) current; 1252 } else { 1253 String title = getString(R.string.search_results_title); 1254 mSearchResultsFragment = (SearchResultsSummary) switchToFragment( 1255 SearchResultsSummary.class.getName(), null, false, true, title, true); 1256 } 1257 mSearchMenuItemExpanded = true; 1258 } 1259 1260 public void needToRevertToInitialFragment() { 1261 mNeedToRevertToInitialFragment = true; 1262 } 1263 1264 private void revertToInitialFragment() { 1265 mNeedToRevertToInitialFragment = false; 1266 mSearchResultsFragment = null; 1267 mSearchMenuItemExpanded = false; 1268 getFragmentManager().popBackStackImmediate(SettingsActivity.BACK_STACK_PREFS, 1269 FragmentManager.POP_BACK_STACK_INCLUSIVE); 1270 mSearchMenuItem.collapseActionView(); 1271 } 1272} 1273