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