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