OSDN Git Service

am 8fc9b5b6: am 2e006b2b: am b7e865ee: (-s ours) am 0431bc18: am e7e0c03f: DO NOT...
[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 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 }