OSDN Git Service

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