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