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