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