OSDN Git Service

f67f73f712f68f4c13f92a588ac7781a8f53f748
[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.ActivityManager;
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.res.Configuration;
34 import android.nfc.NfcAdapter;
35 import android.os.AsyncTask;
36 import android.os.Bundle;
37 import android.os.UserHandle;
38 import android.os.UserManager;
39 import android.support.v14.preference.PreferenceFragment;
40 import android.support.v7.preference.Preference;
41 import android.support.v7.preference.PreferenceManager;
42 import android.text.TextUtils;
43 import android.transition.TransitionManager;
44 import android.util.Log;
45 import android.view.Menu;
46 import android.view.MenuInflater;
47 import android.view.MenuItem;
48 import android.view.View;
49 import android.view.View.OnClickListener;
50 import android.view.ViewGroup;
51 import android.widget.Button;
52 import android.widget.SearchView;
53
54 import com.android.internal.util.ArrayUtils;
55 import com.android.settings.Settings.WifiSettingsActivity;
56 import com.android.settings.accessibility.AccessibilitySettings;
57 import com.android.settings.accessibility.AccessibilitySettingsForSetupWizard;
58 import com.android.settings.accessibility.CaptionPropertiesFragment;
59 import com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment;
60 import com.android.settings.accounts.AccountSettings;
61 import com.android.settings.accounts.AccountSyncSettings;
62 import com.android.settings.accounts.ChooseAccountActivity;
63 import com.android.settings.accounts.ManagedProfileSettings;
64 import com.android.settings.accounts.UserAndAccountDashboardFragment;
65 import com.android.settings.applications.AdvancedAppSettings;
66 import com.android.settings.applications.AppAndNotificationDashboardFragment;
67 import com.android.settings.applications.DrawOverlayDetails;
68 import com.android.settings.applications.InstalledAppDetails;
69 import com.android.settings.applications.ManageApplications;
70 import com.android.settings.applications.ManageAssist;
71 import com.android.settings.applications.ManageDomainUrls;
72 import com.android.settings.applications.NotificationApps;
73 import com.android.settings.applications.ProcessStatsSummary;
74 import com.android.settings.applications.ProcessStatsUi;
75 import com.android.settings.applications.UsageAccessDetails;
76 import com.android.settings.applications.VrListenerSettings;
77 import com.android.settings.applications.WriteSettingsDetails;
78 import com.android.settings.bluetooth.BluetoothSettings;
79 import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
80 import com.android.settings.core.instrumentation.SharedPreferencesLogger;
81 import com.android.settings.dashboard.DashboardContainerFragment;
82 import com.android.settings.dashboard.DashboardFeatureProvider;
83 import com.android.settings.dashboard.DashboardSummary;
84 import com.android.settings.dashboard.SearchResultsSummary;
85 import com.android.settings.dashboard.SupportFragment;
86 import com.android.settings.datausage.DataUsageSummary;
87 import com.android.settings.deletionhelper.AutomaticStorageManagerSettings;
88 import com.android.settings.deviceinfo.ImeiInformation;
89 import com.android.settings.deviceinfo.PrivateVolumeForget;
90 import com.android.settings.deviceinfo.PrivateVolumeSettings;
91 import com.android.settings.deviceinfo.PublicVolumeSettings;
92 import com.android.settings.deviceinfo.SimStatus;
93 import com.android.settings.deviceinfo.Status;
94 import com.android.settings.deviceinfo.StorageDashboardFragment;
95 import com.android.settings.deviceinfo.StorageSettings;
96 import com.android.settings.display.NightDisplaySettings;
97 import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
98 import com.android.settings.enterprise.EnterprisePrivacySettings;
99 import com.android.settings.fuelgauge.BatterySaverSettings;
100 import com.android.settings.fuelgauge.PowerUsageDetail;
101 import com.android.settings.fuelgauge.PowerUsageSummary;
102 import com.android.settings.gestures.DoubleTapPowerSettings;
103 import com.android.settings.gestures.DoubleTapScreenPreferenceController;
104 import com.android.settings.gestures.DoubleTapScreenSettings;
105 import com.android.settings.gestures.DoubleTwistGestureSettings;
106 import com.android.settings.gestures.GestureSettings;
107 import com.android.settings.gestures.PickupGestureSettings;
108 import com.android.settings.gestures.SwipeToNotificationSettings;
109 import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment;
110 import com.android.settings.inputmethod.InputAndGestureSettings;
111 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
112 import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
113 import com.android.settings.inputmethod.PhysicalKeyboardFragment;
114 import com.android.settings.inputmethod.SpellCheckersSettings;
115 import com.android.settings.inputmethod.UserDictionaryList;
116 import com.android.settings.language.LanguageAndRegionSettings;
117 import com.android.settings.localepicker.LocaleListEditor;
118 import com.android.settings.location.LocationSettings;
119 import com.android.settings.network.NetworkDashboardFragment;
120 import com.android.settings.nfc.AndroidBeam;
121 import com.android.settings.nfc.PaymentSettings;
122 import com.android.settings.notification.AppNotificationSettings;
123 import com.android.settings.notification.ConfigureNotificationSettings;
124 import com.android.settings.notification.NotificationAccessSettings;
125 import com.android.settings.notification.NotificationStation;
126 import com.android.settings.notification.OtherSoundSettings;
127 import com.android.settings.notification.SoundSettings;
128 import com.android.settings.notification.ZenAccessSettings;
129 import com.android.settings.notification.ZenModeAutomationSettings;
130 import com.android.settings.notification.ZenModeEventRuleSettings;
131 import com.android.settings.notification.ZenModePrioritySettings;
132 import com.android.settings.notification.ZenModeScheduleRuleSettings;
133 import com.android.settings.notification.ZenModeSettings;
134 import com.android.settings.notification.ZenModeVisualInterruptionSettings;
135 import com.android.settings.overlay.FeatureFactory;
136 import com.android.settings.print.PrintJobSettingsFragment;
137 import com.android.settings.print.PrintSettingsFragment;
138 import com.android.settings.qstile.DevelopmentTiles;
139 import com.android.settings.search.DynamicIndexableContentMonitor;
140 import com.android.settings.search.Index;
141 import com.android.settings.sim.SimSettings;
142 import com.android.settings.system.SystemDashboardFragment;
143 import com.android.settings.tts.TextToSpeechSettings;
144 import com.android.settings.users.UserSettings;
145 import com.android.settings.vpn2.VpnSettings;
146 import com.android.settings.wfd.WifiDisplaySettings;
147 import com.android.settings.widget.SwitchBar;
148 import com.android.settings.wifi.AdvancedWifiSettings;
149 import com.android.settings.wifi.SavedAccessPointsWifiSettings;
150 import com.android.settings.wifi.WifiAPITest;
151 import com.android.settings.wifi.WifiInfo;
152 import com.android.settings.wifi.WifiSettings;
153 import com.android.settings.wifi.p2p.WifiP2pSettings;
154 import com.android.settingslib.drawer.DashboardCategory;
155 import com.android.settingslib.drawer.SettingsDrawerActivity;
156 import com.android.settingslib.drawer.Tile;
157
158 import java.net.URISyntaxException;
159 import java.util.ArrayList;
160 import java.util.List;
161 import java.util.Set;
162
163 public class SettingsActivity extends SettingsDrawerActivity
164         implements PreferenceManager.OnPreferenceTreeClickListener,
165         PreferenceFragment.OnPreferenceStartFragmentCallback,
166         ButtonBarHandler, FragmentManager.OnBackStackChangedListener,
167         SearchView.OnQueryTextListener, SearchView.OnCloseListener,
168         MenuItem.OnActionExpandListener {
169
170     private static final String LOG_TAG = "Settings";
171
172     private static final int LOADER_ID_INDEXABLE_CONTENT_MONITOR = 1;
173
174     // Constants for state save/restore
175     private static final String SAVE_KEY_CATEGORIES = ":settings:categories";
176     private static final String SAVE_KEY_SEARCH_MENU_EXPANDED = ":settings:search_menu_expanded";
177     private static final String SAVE_KEY_SEARCH_QUERY = ":settings:search_query";
178     private static final String SAVE_KEY_SHOW_HOME_AS_UP = ":settings:show_home_as_up";
179     private static final String SAVE_KEY_SHOW_SEARCH = ":settings:show_search";
180
181     /**
182      * When starting this activity, the invoking Intent can contain this extra
183      * string to specify which fragment should be initially displayed.
184      * <p/>Starting from Key Lime Pie, when this argument is passed in, the activity
185      * will call isValidFragment() to confirm that the fragment class name is valid for this
186      * activity.
187      */
188     public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment";
189
190     /**
191      * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
192      * this extra can also be specified to supply a Bundle of arguments to pass
193      * to that fragment when it is instantiated during the initial creation
194      * of the activity.
195      */
196     public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
197
198     /**
199      * Fragment "key" argument passed thru {@link #EXTRA_SHOW_FRAGMENT_ARGUMENTS}
200      */
201     public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
202
203     public static final String BACK_STACK_PREFS = ":settings:prefs";
204
205     // extras that allow any preference activity to be launched as part of a wizard
206
207     // show Back and Next buttons? takes boolean parameter
208     // Back will then return RESULT_CANCELED and Next RESULT_OK
209     protected static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
210
211     // add a Skip button?
212     private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip";
213
214     // specify custom text for the Back or Next buttons, or cause a button to not appear
215     // at all by setting it to null
216     protected static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
217     protected static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
218
219     /**
220      * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
221      * those extra can also be specify to supply the title or title res id to be shown for
222      * that fragment.
223      */
224     public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":settings:show_fragment_title";
225     /**
226      * The package name used to resolve the title resource id.
227      */
228     public static final String EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME =
229             ":settings:show_fragment_title_res_package_name";
230     public static final String EXTRA_SHOW_FRAGMENT_TITLE_RESID =
231             ":settings:show_fragment_title_resid";
232     public static final String EXTRA_SHOW_FRAGMENT_AS_SHORTCUT =
233             ":settings:show_fragment_as_shortcut";
234
235     public static final String EXTRA_SHOW_FRAGMENT_AS_SUBSETTING =
236             ":settings:show_fragment_as_subsetting";
237
238     public static final String EXTRA_HIDE_DRAWER = ":settings:hide_drawer";
239
240     public static final String META_DATA_KEY_FRAGMENT_CLASS =
241         "com.android.settings.FRAGMENT_CLASS";
242
243     private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
244
245     private static final String EMPTY_QUERY = "";
246
247     private static final int REQUEST_SUGGESTION = 42;
248
249     private String mFragmentClass;
250
251     private CharSequence mInitialTitle;
252     private int mInitialTitleResId;
253
254     // Show only these settings for restricted users
255     private String[] SETTINGS_FOR_RESTRICTED = {
256             //wireless_section
257             WifiSettingsActivity.class.getName(),
258             Settings.BluetoothSettingsActivity.class.getName(),
259             Settings.DataUsageSummaryActivity.class.getName(),
260             Settings.SimSettingsActivity.class.getName(),
261             Settings.WirelessSettingsActivity.class.getName(),
262             //device_section
263             Settings.HomeSettingsActivity.class.getName(),
264             Settings.SoundSettingsActivity.class.getName(),
265             Settings.DisplaySettingsActivity.class.getName(),
266             Settings.StorageSettingsActivity.class.getName(),
267             Settings.ManageApplicationsActivity.class.getName(),
268             Settings.PowerUsageSummaryActivity.class.getName(),
269             Settings.GestureSettingsActivity.class.getName(),
270             //personal_section
271             Settings.LocationSettingsActivity.class.getName(),
272             Settings.SecuritySettingsActivity.class.getName(),
273             Settings.InputMethodAndLanguageSettingsActivity.class.getName(),
274             Settings.UserSettingsActivity.class.getName(),
275             Settings.AccountSettingsActivity.class.getName(),
276             //system_section
277             Settings.DateTimeSettingsActivity.class.getName(),
278             Settings.DeviceInfoSettingsActivity.class.getName(),
279             Settings.AccessibilitySettingsActivity.class.getName(),
280             Settings.PrintSettingsActivity.class.getName(),
281             Settings.PaymentSettingsActivity.class.getName(),
282             Settings.EnterprisePrivacySettingsActivity.class.getName(),
283
284             // New IA
285             // Home page
286             Settings.NetworkDashboardActivity.class.getName(),
287             Settings.ConnectedDeviceDashboardActivity.class.getName(),
288             Settings.AppAndNotificationDashboardActivity.class.getName(),
289             "com.android.settings.Settings.BatteryDashboardAlias",
290             "com.android.settings.Settings.DisplayDashboardAlias",
291             "com.android.settings.Settings.SoundDashboardAlias",
292             "com.android.settings.Settings.SecurityDashboardAlias",
293             Settings.UserAndAccountDashboardActivity.class.getName(),
294             Settings.SystemDashboardActivity.class.getName(),
295             Settings.SupportDashboardActivity.class.getName(),
296             // Home page > Apps & Notifications
297             "com.android.settings.Settings.ManageApplicationsDashboardAlias",
298             "com.android.settings.Settings.PaymentSettingsDashboardAlias",
299             // Home page > Network & Internet
300             "com.android.settings.Settings.WifiDashboardAlias",
301             "com.android.settings.Settings.DataUsageDashboardAlias",
302             // Home page > Security
303             "com.android.settings.Settings.LocationDashboardAlias",
304             // Home page > System
305             Settings.LanguageAndRegionSettingsActivity.class.getName(),
306             Settings.InputAndGestureSettingsActivity.class.getName(),
307             "com.android.settings.Settings.DateTimeDashboardAlias",
308             "com.android.settings.Settings.AccessibilityDashboardAlias",
309             "com.android.settings.Settings.AboutDeviceDashboardAlias",
310     };
311
312     private static final String[] ENTRY_FRAGMENTS = {
313             WirelessSettings.class.getName(),
314             WifiSettings.class.getName(),
315             AdvancedWifiSettings.class.getName(),
316             SavedAccessPointsWifiSettings.class.getName(),
317             BluetoothSettings.class.getName(),
318             SimSettings.class.getName(),
319             TetherSettings.class.getName(),
320             WifiP2pSettings.class.getName(),
321             VpnSettings.class.getName(),
322             DateTimeSettings.class.getName(),
323             LocaleListEditor.class.getName(),
324             InputMethodAndLanguageSettings.class.getName(),
325             AvailableVirtualKeyboardFragment.class.getName(),
326             InputAndGestureSettings.class.getName(),
327             LanguageAndRegionSettings.class.getName(),
328             SpellCheckersSettings.class.getName(),
329             UserDictionaryList.class.getName(),
330             UserDictionarySettings.class.getName(),
331             HomeSettings.class.getName(),
332             DisplaySettings.class.getName(),
333             DeviceInfoSettings.class.getName(),
334             ManageApplications.class.getName(),
335             NotificationApps.class.getName(),
336             ManageAssist.class.getName(),
337             ProcessStatsUi.class.getName(),
338             NotificationStation.class.getName(),
339             LocationSettings.class.getName(),
340             SecuritySettings.class.getName(),
341             UsageAccessDetails.class.getName(),
342             PrivacySettings.class.getName(),
343             DeviceAdminSettings.class.getName(),
344             AccessibilitySettings.class.getName(),
345             AccessibilitySettingsForSetupWizard.class.getName(),
346             CaptionPropertiesFragment.class.getName(),
347             ToggleDaltonizerPreferenceFragment.class.getName(),
348             TextToSpeechSettings.class.getName(),
349             StorageSettings.class.getName(),
350             PrivateVolumeForget.class.getName(),
351             PrivateVolumeSettings.class.getName(),
352             PublicVolumeSettings.class.getName(),
353             DevelopmentSettings.class.getName(),
354             AndroidBeam.class.getName(),
355             WifiDisplaySettings.class.getName(),
356             PowerUsageSummary.class.getName(),
357             AccountSyncSettings.class.getName(),
358             AccountSettings.class.getName(),
359             GestureSettings.class.getName(),
360             SwipeToNotificationSettings.class.getName(),
361             DoubleTapPowerSettings.class.getName(),
362             DoubleTapScreenSettings.class.getName(),
363             PickupGestureSettings.class.getName(),
364             DoubleTwistGestureSettings.class.getName(),
365             CryptKeeperSettings.class.getName(),
366             DataUsageSummary.class.getName(),
367             DreamSettings.class.getName(),
368             UserSettings.class.getName(),
369             NotificationAccessSettings.class.getName(),
370             ZenAccessSettings.class.getName(),
371             PrintSettingsFragment.class.getName(),
372             PrintJobSettingsFragment.class.getName(),
373             TrustedCredentialsSettings.class.getName(),
374             PaymentSettings.class.getName(),
375             KeyboardLayoutPickerFragment.class.getName(),
376             PhysicalKeyboardFragment.class.getName(),
377             ZenModeSettings.class.getName(),
378             SoundSettings.class.getName(),
379             ConfigureNotificationSettings.class.getName(),
380             ChooseLockPassword.ChooseLockPasswordFragment.class.getName(),
381             ChooseLockPattern.ChooseLockPatternFragment.class.getName(),
382             InstalledAppDetails.class.getName(),
383             BatterySaverSettings.class.getName(),
384             AppNotificationSettings.class.getName(),
385             OtherSoundSettings.class.getName(),
386             ApnSettings.class.getName(),
387             ApnEditor.class.getName(),
388             WifiCallingSettings.class.getName(),
389             ZenModePrioritySettings.class.getName(),
390             ZenModeAutomationSettings.class.getName(),
391             ZenModeScheduleRuleSettings.class.getName(),
392             ZenModeEventRuleSettings.class.getName(),
393             ZenModeVisualInterruptionSettings.class.getName(),
394             ProcessStatsUi.class.getName(),
395             PowerUsageDetail.class.getName(),
396             ProcessStatsSummary.class.getName(),
397             DrawOverlayDetails.class.getName(),
398             WriteSettingsDetails.class.getName(),
399             AdvancedAppSettings.class.getName(),
400             WallpaperTypeSettings.class.getName(),
401             VrListenerSettings.class.getName(),
402             ManagedProfileSettings.class.getName(),
403             ChooseAccountActivity.class.getName(),
404             IccLockSettings.class.getName(),
405             ImeiInformation.class.getName(),
406             SimStatus.class.getName(),
407             Status.class.getName(),
408             TestingSettings.class.getName(),
409             WifiAPITest.class.getName(),
410             WifiInfo.class.getName(),
411             MasterClear.class.getName(),
412             NightDisplaySettings.class.getName(),
413             ManageDomainUrls.class.getName(),
414             AutomaticStorageManagerSettings.class.getName(),
415             SupportFragment.class.getName(),
416             StorageDashboardFragment.class.getName(),
417             SystemDashboardFragment.class.getName(),
418             NetworkDashboardFragment.class.getName(),
419             ConnectedDeviceDashboardFragment.class.getName(),
420             AppAndNotificationDashboardFragment.class.getName(),
421             UserAndAccountDashboardFragment.class.getName(),
422             EnterprisePrivacySettings.class.getName(),
423     };
424
425
426     private static final String[] LIKE_SHORTCUT_INTENT_ACTION_ARRAY = {
427             "android.settings.APPLICATION_DETAILS_SETTINGS"
428     };
429
430     private SharedPreferences mDevelopmentPreferences;
431     private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
432
433     private boolean mBatteryPresent = true;
434     private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
435         @Override
436         public void onReceive(Context context, Intent intent) {
437             String action = intent.getAction();
438             if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
439                 boolean batteryPresent = Utils.isBatteryPresent(intent);
440
441                 if (mBatteryPresent != batteryPresent) {
442                     mBatteryPresent = batteryPresent;
443                     updateTilesList();
444                 }
445             }
446         }
447     };
448
449     private final BroadcastReceiver mUserAddRemoveReceiver = new BroadcastReceiver() {
450         @Override
451         public void onReceive(Context context, Intent intent) {
452             String action = intent.getAction();
453             if (action.equals(Intent.ACTION_USER_ADDED)
454                     || action.equals(Intent.ACTION_USER_REMOVED)) {
455                 Index.getInstance(getApplicationContext()).update();
456             }
457         }
458     };
459
460     private final DynamicIndexableContentMonitor mDynamicIndexableContentMonitor =
461             new DynamicIndexableContentMonitor();
462
463     private ActionBar mActionBar;
464     private SwitchBar mSwitchBar;
465
466     private Button mNextButton;
467
468     private boolean mDisplayHomeAsUpEnabled;
469     private boolean mDisplaySearch;
470
471     private boolean mIsShowingDashboard;
472     private boolean mIsShortcut;
473
474     private ViewGroup mContent;
475
476     private SearchView mSearchView;
477     private MenuItem mSearchMenuItem;
478     private boolean mSearchMenuItemExpanded = false;
479     private SearchResultsSummary mSearchResultsFragment;
480     private String mSearchQuery;
481
482     // Categories
483     private ArrayList<DashboardCategory> mCategories = new ArrayList<DashboardCategory>();
484
485     private static final String MSG_DATA_FORCE_REFRESH = "msg_data_force_refresh";
486
487     private boolean mNeedToRevertToInitialFragment = false;
488
489     private DashboardFeatureProvider mDashboardFeatureProvider;
490     private Intent mResultIntentData;
491     private ComponentName mCurrentSuggestion;
492
493     public SwitchBar getSwitchBar() {
494         return mSwitchBar;
495     }
496
497     @Override
498     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
499         startPreferencePanel(pref.getFragment(), pref.getExtras(), -1, pref.getTitle(),
500                 null, 0);
501         return true;
502     }
503
504     @Override
505     public boolean onPreferenceTreeClick(Preference preference) {
506         return false;
507     }
508
509     @Override
510     public void onConfigurationChanged(Configuration newConfig) {
511         super.onConfigurationChanged(newConfig);
512         Index.getInstance(this).update();
513     }
514
515     @Override
516     protected void onStart() {
517         super.onStart();
518
519         if (mNeedToRevertToInitialFragment) {
520             revertToInitialFragment();
521         }
522     }
523
524     @Override
525     public boolean onCreateOptionsMenu(Menu menu) {
526         if (!mDisplaySearch) {
527             return false;
528         }
529
530         MenuInflater inflater = getMenuInflater();
531         inflater.inflate(R.menu.options_menu, menu);
532
533         // Cache the search query (can be overriden by the OnQueryTextListener)
534         final String query = mSearchQuery;
535
536         mSearchMenuItem = menu.findItem(R.id.search);
537         mSearchView = (SearchView) mSearchMenuItem.getActionView();
538
539         if (mSearchMenuItem == null || mSearchView == null) {
540             return false;
541         }
542
543         if (mSearchResultsFragment != null) {
544             mSearchResultsFragment.setSearchView(mSearchView);
545         }
546
547         mSearchMenuItem.setOnActionExpandListener(this);
548         mSearchView.setMaxWidth(Integer.MAX_VALUE);
549         mSearchView.setOnQueryTextListener(this);
550         mSearchView.setOnCloseListener(this);
551
552         if (mSearchMenuItemExpanded) {
553             mSearchMenuItem.expandActionView();
554         }
555         mSearchView.setQuery(query, true /* submit */);
556
557         return true;
558     }
559
560     @Override
561     public SharedPreferences getSharedPreferences(String name, int mode) {
562         if (name.equals(getPackageName() + "_preferences")) {
563             return new SharedPreferencesLogger(this, getMetricsTag());
564         }
565         return super.getSharedPreferences(name, mode);
566     }
567
568     private String getMetricsTag() {
569         String tag = getClass().getName();
570         if (getIntent() != null && getIntent().hasExtra(EXTRA_SHOW_FRAGMENT)) {
571             tag = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
572         }
573         if (tag.startsWith("com.android.settings.")) {
574             tag = tag.replace("com.android.settings.", "");
575         }
576         return tag;
577     }
578
579     private static boolean isShortCutIntent(final Intent intent) {
580         Set<String> categories = intent.getCategories();
581         return (categories != null) && categories.contains("com.android.settings.SHORTCUT");
582     }
583
584     private static boolean isLikeShortCutIntent(final Intent intent) {
585         String action = intent.getAction();
586         if (action == null) {
587             return false;
588         }
589         for (int i = 0; i < LIKE_SHORTCUT_INTENT_ACTION_ARRAY.length; i++) {
590             if (LIKE_SHORTCUT_INTENT_ACTION_ARRAY[i].equals(action)) return true;
591         }
592         return false;
593     }
594
595     @Override
596     protected void onCreate(Bundle savedState) {
597         super.onCreate(savedState);
598         long startTime = System.currentTimeMillis();
599         mDashboardFeatureProvider =
600                 FeatureFactory.getFactory(this).getDashboardFeatureProvider(this);
601         // Should happen before any call to getIntent()
602         getMetaData();
603
604         final Intent intent = getIntent();
605         if (intent.hasExtra(EXTRA_UI_OPTIONS)) {
606             getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));
607         }
608         if (intent.getBooleanExtra(EXTRA_HIDE_DRAWER, false)) {
609             setIsDrawerPresent(false);
610         }
611
612         mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
613                 Context.MODE_PRIVATE);
614
615         // Getting Intent properties can only be done after the super.onCreate(...)
616         final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
617
618         mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||
619                 intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);
620
621         final ComponentName cn = intent.getComponent();
622         final String className = cn.getClassName();
623
624         mIsShowingDashboard = className.equals(Settings.class.getName())
625                 || className.equals(Settings.WirelessSettings.class.getName())
626                 || className.equals(Settings.DeviceSettings.class.getName())
627                 || className.equals(Settings.PersonalSettings.class.getName())
628                 || className.equals(Settings.WirelessSettings.class.getName());
629
630         // This is a "Sub Settings" when:
631         // - this is a real SubSettings
632         // - or :settings:show_fragment_as_subsetting is passed to the Intent
633         final boolean isSubSettings = this instanceof SubSettings ||
634                 intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);
635
636         // If this is a sub settings, then apply the SubSettings Theme for the ActionBar content insets
637         if (isSubSettings) {
638             // Check also that we are not a Theme Dialog as we don't want to override them
639             final int themeResId = getThemeResId();
640             if (themeResId != R.style.Theme_DialogWhenLarge &&
641                     themeResId != R.style.Theme_SubSettingsDialogWhenLarge) {
642                 setTheme(R.style.Theme_SubSettings);
643             }
644         }
645
646         setContentView(mIsShowingDashboard ?
647                 R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
648
649         mContent = (ViewGroup) findViewById(R.id.main_content);
650
651         getFragmentManager().addOnBackStackChangedListener(this);
652
653         if (mIsShowingDashboard) {
654             // Run the Index update only if we have some space
655             if (!Utils.isLowStorage(this)) {
656                 long indexStartTime = System.currentTimeMillis();
657                 Index.getInstance(getApplicationContext()).update();
658                 if (DEBUG_TIMING) Log.d(LOG_TAG, "Index.update() took "
659                         + (System.currentTimeMillis() - indexStartTime) + " ms");
660             } else {
661                 Log.w(LOG_TAG, "Cannot update the Indexer as we are running low on storage space!");
662             }
663         }
664
665         if (savedState != null) {
666             // We are restarting from a previous saved state; used that to initialize, instead
667             // of starting fresh.
668             mSearchMenuItemExpanded = savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED);
669             mSearchQuery = savedState.getString(SAVE_KEY_SEARCH_QUERY);
670             setTitleFromIntent(intent);
671
672             ArrayList<DashboardCategory> categories =
673                     savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES);
674             if (categories != null) {
675                 mCategories.clear();
676                 mCategories.addAll(categories);
677                 setTitleFromBackStack();
678             }
679
680             mDisplayHomeAsUpEnabled = savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP);
681             mDisplaySearch = savedState.getBoolean(SAVE_KEY_SHOW_SEARCH);
682
683         } else {
684             if (!mIsShowingDashboard) {
685                 mDisplaySearch = false;
686                 // UP will be shown only if it is a sub settings
687                 if (mIsShortcut) {
688                     mDisplayHomeAsUpEnabled = isSubSettings;
689                 } else if (isSubSettings) {
690                     mDisplayHomeAsUpEnabled = true;
691                 } else {
692                     mDisplayHomeAsUpEnabled = false;
693                 }
694                 setTitleFromIntent(intent);
695
696                 Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
697                 switchToFragment(initialFragmentName, initialArguments, true, false,
698                         mInitialTitleResId, mInitialTitle, false);
699             } else {
700                 // No UP affordance if we are displaying the main Dashboard
701                 mDisplayHomeAsUpEnabled = false;
702                 // Show Search affordance
703                 mDisplaySearch = true;
704                 mInitialTitleResId = R.string.dashboard_title;
705
706                 // add argument to indicate which settings tab should be initially selected
707                 final Bundle args = new Bundle();
708                 final String extraName = DashboardContainerFragment.EXTRA_SELECT_SETTINGS_TAB;
709                 args.putString(extraName, intent.getStringExtra(extraName));
710                 if (isDashboardFeatureEnabled()) {
711                     switchToFragment(DashboardSummary.class.getName(), args, false, false,
712                             mInitialTitleResId, mInitialTitle, false);
713                 } else {
714                     switchToFragment(DashboardContainerFragment.class.getName(), args, false, false,
715                             mInitialTitleResId, mInitialTitle, false);
716                 }
717             }
718         }
719
720         mActionBar = getActionBar();
721         if (mActionBar != null) {
722             mActionBar.setDisplayHomeAsUpEnabled(mDisplayHomeAsUpEnabled);
723             mActionBar.setHomeButtonEnabled(mDisplayHomeAsUpEnabled);
724         }
725         mSwitchBar = (SwitchBar) findViewById(R.id.switch_bar);
726         if (mSwitchBar != null) {
727             mSwitchBar.setMetricsTag(getMetricsTag());
728         }
729
730         // see if we should show Back/Next buttons
731         if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
732
733             View buttonBar = findViewById(R.id.button_bar);
734             if (buttonBar != null) {
735                 buttonBar.setVisibility(View.VISIBLE);
736
737                 Button backButton = (Button)findViewById(R.id.back_button);
738                 backButton.setOnClickListener(new OnClickListener() {
739                     public void onClick(View v) {
740                         setResult(RESULT_CANCELED, getResultIntentData());
741                         finish();
742                     }
743                 });
744                 Button skipButton = (Button)findViewById(R.id.skip_button);
745                 skipButton.setOnClickListener(new OnClickListener() {
746                     public void onClick(View v) {
747                         setResult(RESULT_OK, getResultIntentData());
748                         finish();
749                     }
750                 });
751                 mNextButton = (Button)findViewById(R.id.next_button);
752                 mNextButton.setOnClickListener(new OnClickListener() {
753                     public void onClick(View v) {
754                         setResult(RESULT_OK, getResultIntentData());
755                         finish();
756                     }
757                 });
758
759                 // set our various button parameters
760                 if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
761                     String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
762                     if (TextUtils.isEmpty(buttonText)) {
763                         mNextButton.setVisibility(View.GONE);
764                     }
765                     else {
766                         mNextButton.setText(buttonText);
767                     }
768                 }
769                 if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
770                     String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
771                     if (TextUtils.isEmpty(buttonText)) {
772                         backButton.setVisibility(View.GONE);
773                     }
774                     else {
775                         backButton.setText(buttonText);
776                     }
777                 }
778                 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
779                     skipButton.setVisibility(View.VISIBLE);
780                 }
781             }
782         }
783
784         if (DEBUG_TIMING) Log.d(LOG_TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
785                 + " ms");
786     }
787
788     public void setDisplaySearchMenu(boolean displaySearch) {
789         if (displaySearch != mDisplaySearch) {
790             mDisplaySearch = displaySearch;
791             invalidateOptionsMenu();
792         }
793     }
794
795     private void setTitleFromIntent(Intent intent) {
796         final int initialTitleResId = intent.getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, -1);
797         if (initialTitleResId > 0) {
798             mInitialTitle = null;
799             mInitialTitleResId = initialTitleResId;
800
801             final String initialTitleResPackageName = intent.getStringExtra(
802                     EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME);
803             if (initialTitleResPackageName != null) {
804                 try {
805                     Context authContext = createPackageContextAsUser(initialTitleResPackageName,
806                             0 /* flags */, new UserHandle(UserHandle.myUserId()));
807                     mInitialTitle = authContext.getResources().getText(mInitialTitleResId);
808                     setTitle(mInitialTitle);
809                     mInitialTitleResId = -1;
810                     return;
811                 } catch (NameNotFoundException e) {
812                     Log.w(LOG_TAG, "Could not find package" + initialTitleResPackageName);
813                 }
814             } else {
815                 setTitle(mInitialTitleResId);
816             }
817         } else {
818             mInitialTitleResId = -1;
819             final String initialTitle = intent.getStringExtra(EXTRA_SHOW_FRAGMENT_TITLE);
820             mInitialTitle = (initialTitle != null) ? initialTitle : getTitle();
821             setTitle(mInitialTitle);
822         }
823     }
824
825     @Override
826     public void onBackStackChanged() {
827         setTitleFromBackStack();
828     }
829
830     private void setTitleFromBackStack() {
831         final int count = getFragmentManager().getBackStackEntryCount();
832
833         if (count == 0) {
834             if (mInitialTitleResId > 0) {
835                 setTitle(mInitialTitleResId);
836             } else {
837                 setTitle(mInitialTitle);
838             }
839             return;
840         }
841
842         FragmentManager.BackStackEntry bse = getFragmentManager().getBackStackEntryAt(count - 1);
843         setTitleFromBackStackEntry(bse);
844     }
845
846     private void setTitleFromBackStackEntry(FragmentManager.BackStackEntry bse) {
847         final CharSequence title;
848         final int titleRes = bse.getBreadCrumbTitleRes();
849         if (titleRes > 0) {
850             title = getText(titleRes);
851         } else {
852             title = bse.getBreadCrumbTitle();
853         }
854         if (title != null) {
855             setTitle(title);
856         }
857     }
858
859     @Override
860     protected void onSaveInstanceState(Bundle outState) {
861         super.onSaveInstanceState(outState);
862
863         if (mCategories.size() > 0) {
864             outState.putParcelableArrayList(SAVE_KEY_CATEGORIES, mCategories);
865         }
866
867         outState.putBoolean(SAVE_KEY_SHOW_HOME_AS_UP, mDisplayHomeAsUpEnabled);
868         outState.putBoolean(SAVE_KEY_SHOW_SEARCH, mDisplaySearch);
869
870         if (mDisplaySearch) {
871             // The option menus are created if the ActionBar is visible and they are also created
872             // asynchronously. If you launch Settings with an Intent action like
873             // android.intent.action.POWER_USAGE_SUMMARY and at the same time your device is locked
874             // thru a LockScreen, onCreateOptionsMenu() is not yet called and references to the search
875             // menu item and search view are null.
876             boolean isExpanded = (mSearchMenuItem != null) && mSearchMenuItem.isActionViewExpanded();
877             outState.putBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED, isExpanded);
878
879             String query = (mSearchView != null) ? mSearchView.getQuery().toString() : EMPTY_QUERY;
880             outState.putString(SAVE_KEY_SEARCH_QUERY, query);
881         }
882     }
883
884     @Override
885     protected void onResume() {
886         super.onResume();
887
888         mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
889             @Override
890             public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
891                 updateTilesList();
892             }
893         };
894         mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
895                 mDevelopmentPreferencesListener);
896
897         registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
898         registerReceiver(mUserAddRemoveReceiver, new IntentFilter(Intent.ACTION_USER_ADDED));
899         registerReceiver(mUserAddRemoveReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
900
901         mDynamicIndexableContentMonitor.register(this, LOADER_ID_INDEXABLE_CONTENT_MONITOR);
902
903         if(mDisplaySearch && !TextUtils.isEmpty(mSearchQuery)) {
904             onQueryTextSubmit(mSearchQuery);
905         }
906         updateTilesList();
907     }
908
909     @Override
910     protected void onPause() {
911         super.onPause();
912         unregisterReceiver(mBatteryInfoReceiver);
913         unregisterReceiver(mUserAddRemoveReceiver);
914         mDynamicIndexableContentMonitor.unregister();
915     }
916
917     @Override
918     public void onDestroy() {
919         super.onDestroy();
920
921         mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
922                 mDevelopmentPreferencesListener);
923         mDevelopmentPreferencesListener = null;
924     }
925
926     protected boolean isValidFragment(String fragmentName) {
927         // Almost all fragments are wrapped in this,
928         // except for a few that have their own activities.
929         for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
930             if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
931         }
932         return false;
933     }
934
935     @Override
936     public Intent getIntent() {
937         Intent superIntent = super.getIntent();
938         String startingFragment = getStartingFragmentClass(superIntent);
939         // This is called from super.onCreate, isMultiPane() is not yet reliable
940         // Do not use onIsHidingHeaders either, which relies itself on this method
941         if (startingFragment != null) {
942             Intent modIntent = new Intent(superIntent);
943             modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
944             Bundle args = superIntent.getExtras();
945             if (args != null) {
946                 args = new Bundle(args);
947             } else {
948                 args = new Bundle();
949             }
950             args.putParcelable("intent", superIntent);
951             modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
952             return modIntent;
953         }
954         return superIntent;
955     }
956
957     /**
958      * Checks if the component name in the intent is different from the Settings class and
959      * returns the class name to load as a fragment.
960      */
961     private String getStartingFragmentClass(Intent intent) {
962         if (mFragmentClass != null) return mFragmentClass;
963
964         String intentClass = intent.getComponent().getClassName();
965         if (intentClass.equals(getClass().getName())) return null;
966
967         if ("com.android.settings.ManageApplications".equals(intentClass)
968                 || "com.android.settings.RunningServices".equals(intentClass)
969                 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
970             // Old names of manage apps.
971             intentClass = com.android.settings.applications.ManageApplications.class.getName();
972         }
973
974         return intentClass;
975     }
976
977     /**
978      * Start a new fragment containing a preference panel.  If the preferences
979      * are being displayed in multi-pane mode, the given fragment class will
980      * be instantiated and placed in the appropriate pane.  If running in
981      * single-pane mode, a new activity will be launched in which to show the
982      * fragment.
983      *
984      * @param fragmentClass Full name of the class implementing the fragment.
985      * @param args Any desired arguments to supply to the fragment.
986      * @param titleRes Optional resource identifier of the title of this
987      * fragment.
988      * @param titleText Optional text of the title of this fragment.
989      * @param resultTo Optional fragment that result data should be sent to.
990      * If non-null, resultTo.onActivityResult() will be called when this
991      * preference panel is done.  The launched panel must use
992      * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
993      * @param resultRequestCode If resultTo is non-null, this is the caller's
994      * request code to be received with the result.
995      */
996     public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
997             CharSequence titleText, Fragment resultTo, int resultRequestCode) {
998         String title = null;
999         if (titleRes < 0) {
1000             if (titleText != null) {
1001                 title = titleText.toString();
1002             } else {
1003                 // There not much we can do in that case
1004                 title = "";
1005             }
1006         }
1007         Utils.startWithFragment(this, fragmentClass, args, resultTo, resultRequestCode,
1008                 titleRes, title, mIsShortcut);
1009     }
1010
1011     /**
1012      * Start a new fragment in a new activity containing a preference panel for a given user. If the
1013      * preferences are being displayed in multi-pane mode, the given fragment class will be
1014      * instantiated and placed in the appropriate pane. If running in single-pane mode, a new
1015      * activity will be launched in which to show the fragment.
1016      *
1017      * @param fragmentClass Full name of the class implementing the fragment.
1018      * @param args Any desired arguments to supply to the fragment.
1019      * @param titleRes Optional resource identifier of the title of this fragment.
1020      * @param titleText Optional text of the title of this fragment.
1021      * @param userHandle The user for which the panel has to be started.
1022      */
1023     public void startPreferencePanelAsUser(String fragmentClass, Bundle args, int titleRes,
1024             CharSequence titleText, UserHandle userHandle) {
1025         // This is a workaround.
1026         //
1027         // Calling startWithFragmentAsUser() without specifying FLAG_ACTIVITY_NEW_TASK to the intent
1028         // starting the fragment could cause a native stack corruption. See b/17523189. However,
1029         // adding that flag and start the preference panel with the same UserHandler will make it
1030         // impossible to use back button to return to the previous screen. See b/20042570.
1031         //
1032         // We work around this issue by adding FLAG_ACTIVITY_NEW_TASK to the intent, while doing
1033         // another check here to call startPreferencePanel() instead of startWithFragmentAsUser()
1034         // when we're calling it as the same user.
1035         if (userHandle.getIdentifier() == UserHandle.myUserId()) {
1036             startPreferencePanel(fragmentClass, args, titleRes, titleText, null, 0);
1037         } else {
1038             String title = null;
1039             if (titleRes < 0) {
1040                 if (titleText != null) {
1041                     title = titleText.toString();
1042                 } else {
1043                     // There not much we can do in that case
1044                     title = "";
1045                 }
1046             }
1047             Utils.startWithFragmentAsUser(this, fragmentClass, args,
1048                     titleRes, title, mIsShortcut, userHandle);
1049         }
1050     }
1051
1052     /**
1053      * Called by a preference panel fragment to finish itself.
1054      *
1055      * @param caller The fragment that is asking to be finished.
1056      * @param resultCode Optional result code to send back to the original
1057      * launching fragment.
1058      * @param resultData Optional result data to send back to the original
1059      * launching fragment.
1060      */
1061     public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
1062         setResult(resultCode, resultData);
1063         finish();
1064     }
1065
1066     /**
1067      * Start a new fragment.
1068      *
1069      * @param fragment The fragment to start
1070      * @param push If true, the current fragment will be pushed onto the back stack.  If false,
1071      * the current fragment will be replaced.
1072      */
1073     public void startPreferenceFragment(Fragment fragment, boolean push) {
1074         FragmentTransaction transaction = getFragmentManager().beginTransaction();
1075         transaction.replace(R.id.main_content, fragment);
1076         if (push) {
1077             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
1078             transaction.addToBackStack(BACK_STACK_PREFS);
1079         } else {
1080             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
1081         }
1082         transaction.commitAllowingStateLoss();
1083     }
1084
1085     /**
1086      * Switch to a specific Fragment with taking care of validation, Title and BackStack
1087      */
1088     private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate,
1089             boolean addToBackStack, int titleResId, CharSequence title, boolean withTransition) {
1090         if (validate && !isValidFragment(fragmentName)) {
1091             throw new IllegalArgumentException("Invalid fragment for this activity: "
1092                     + fragmentName);
1093         }
1094         Fragment f = Fragment.instantiate(this, fragmentName, args);
1095         FragmentTransaction transaction = getFragmentManager().beginTransaction();
1096         transaction.replace(R.id.main_content, f);
1097         if (withTransition) {
1098             TransitionManager.beginDelayedTransition(mContent);
1099         }
1100         if (addToBackStack) {
1101             transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS);
1102         }
1103         if (titleResId > 0) {
1104             transaction.setBreadCrumbTitle(titleResId);
1105         } else if (title != null) {
1106             transaction.setBreadCrumbTitle(title);
1107         }
1108         transaction.commitAllowingStateLoss();
1109         getFragmentManager().executePendingTransactions();
1110         return f;
1111     }
1112
1113     private void updateTilesList() {
1114         // Generally the items that are will be changing from these updates will
1115         // not be in the top list of tiles, so run it in the background and the
1116         // SettingsDrawerActivity will pick up on the updates automatically.
1117         AsyncTask.execute(new Runnable() {
1118             @Override
1119             public void run() {
1120                 doUpdateTilesList();
1121             }
1122         });
1123     }
1124
1125     private void doUpdateTilesList() {
1126         PackageManager pm = getPackageManager();
1127         final UserManager um = UserManager.get(this);
1128         final boolean isAdmin = um.isAdminUser();
1129
1130         String packageName = getPackageName();
1131         setTileEnabled(new ComponentName(packageName, WifiSettingsActivity.class.getName()),
1132                 pm.hasSystemFeature(PackageManager.FEATURE_WIFI), isAdmin, pm);
1133
1134         setTileEnabled(new ComponentName(packageName,
1135                 Settings.BluetoothSettingsActivity.class.getName()),
1136                 pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH), isAdmin, pm);
1137
1138         setTileEnabled(new ComponentName(packageName,
1139                 Settings.DataUsageSummaryActivity.class.getName()),
1140                 Utils.isBandwidthControlEnabled(), isAdmin, pm);
1141
1142         setTileEnabled(new ComponentName(packageName,
1143                 Settings.SimSettingsActivity.class.getName()),
1144                 Utils.showSimCardTile(this), isAdmin, pm);
1145
1146         setTileEnabled(new ComponentName(packageName,
1147                 Settings.PowerUsageSummaryActivity.class.getName()),
1148                 mBatteryPresent, isAdmin, pm);
1149
1150         setTileEnabled(new ComponentName(packageName,
1151                 Settings.UserSettingsActivity.class.getName()),
1152                 UserHandle.MU_ENABLED && UserManager.supportsMultipleUsers()
1153                 && !Utils.isMonkeyRunning(), isAdmin, pm);
1154
1155         setTileEnabled(new ComponentName(packageName,
1156                         Settings.WirelessSettingsActivity.class.getName()),
1157                 !UserManager.isDeviceInDemoMode(this), isAdmin, pm);
1158
1159         setTileEnabled(new ComponentName(packageName,
1160                         Settings.DateTimeSettingsActivity.class.getName()),
1161                 !UserManager.isDeviceInDemoMode(this), isAdmin, pm);
1162         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
1163         setTileEnabled(new ComponentName(packageName,
1164                         Settings.PaymentSettingsActivity.class.getName()),
1165                 pm.hasSystemFeature(PackageManager.FEATURE_NFC)
1166                         && pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
1167                         && adapter != null && adapter.isEnabled(), isAdmin, pm);
1168
1169         setTileEnabled(new ComponentName(packageName,
1170                 Settings.PrintSettingsActivity.class.getName()),
1171                 pm.hasSystemFeature(PackageManager.FEATURE_PRINTING), isAdmin, pm);
1172
1173         final boolean showDev = mDevelopmentPreferences.getBoolean(
1174                     DevelopmentSettings.PREF_SHOW, android.os.Build.TYPE.equals("eng"))
1175                 && !um.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES);
1176         setTileEnabled(new ComponentName(packageName,
1177                         Settings.DevelopmentSettingsActivity.class.getName()),
1178                 showDev, isAdmin, pm);
1179         setTileEnabled(new ComponentName(packageName,
1180                         Settings.DevelopmentSettingsActivity.DASHBOARD_ALIAS),
1181                 showDev, isAdmin, pm);
1182
1183         // Reveal development-only quick settings tiles
1184         DevelopmentTiles.setTilesEnabled(this, showDev);
1185
1186         if (UserHandle.MU_ENABLED && !isAdmin) {
1187             // When on restricted users, disable all extra categories (but only the settings ones).
1188             List<DashboardCategory> categories;
1189             if (isDashboardFeatureEnabled()) {
1190                 categories = mDashboardFeatureProvider.getAllCategories();
1191             } else {
1192                 categories = getDashboardCategories();
1193             }
1194
1195             for (DashboardCategory category : categories) {
1196                 for (Tile tile : category.tiles) {
1197                     ComponentName component = tile.intent.getComponent();
1198                     if (packageName.equals(component.getPackageName()) && !ArrayUtils.contains(
1199                             SETTINGS_FOR_RESTRICTED, component.getClassName())) {
1200                         setTileEnabled(component, false, isAdmin, pm);
1201                     }
1202                 }
1203             }
1204         }
1205
1206         String backupIntent = getResources().getString(R.string.config_backup_settings_intent);
1207         boolean useDefaultBackup = TextUtils.isEmpty(backupIntent);
1208         setTileEnabled(new ComponentName(packageName,
1209                 Settings.PrivacySettingsActivity.class.getName()), useDefaultBackup, isAdmin, pm);
1210         setTileEnabled(new ComponentName(packageName,
1211                         "com.android.settings.PrivacyDashboardAlias"),
1212                 useDefaultBackup, isAdmin, pm);
1213
1214         boolean hasBackupActivity = false;
1215         if (!useDefaultBackup) {
1216             try {
1217                 Intent intent = Intent.parseUri(backupIntent, 0);
1218                 hasBackupActivity = !getPackageManager().queryIntentActivities(intent, 0).isEmpty();
1219             } catch (URISyntaxException e) {
1220                 Log.e(LOG_TAG, "Invalid backup intent URI!", e);
1221             }
1222         }
1223         setTileEnabled(new ComponentName(packageName,
1224                 BackupSettingsActivity.class.getName()), hasBackupActivity, isAdmin, pm);
1225
1226         setTileEnabled(new ComponentName(packageName,
1227                 Settings.EnterprisePrivacySettingsActivity.class.getName()),
1228                 FeatureFactory.getFactory(this).getEnterprisePrivacyFeatureProvider(this)
1229                         .hasDeviceOwner(), isAdmin, pm);
1230
1231     }
1232
1233     private void setTileEnabled(ComponentName component, boolean enabled, boolean isAdmin,
1234                                 PackageManager pm) {
1235         if (UserHandle.MU_ENABLED && !isAdmin && getPackageName().equals(component.getPackageName())
1236                 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, component.getClassName())) {
1237             enabled = false;
1238         }
1239         setTileEnabled(component, enabled);
1240     }
1241
1242     private void getMetaData() {
1243         try {
1244             ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
1245                     PackageManager.GET_META_DATA);
1246             if (ai == null || ai.metaData == null) return;
1247             mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
1248         } catch (NameNotFoundException nnfe) {
1249             // No recovery
1250             Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());
1251         }
1252     }
1253
1254     @Override
1255     protected boolean isDashboardFeatureEnabled() {
1256         if (mDashboardFeatureProvider == null) {
1257             mDashboardFeatureProvider =
1258                     FeatureFactory.getFactory(this).getDashboardFeatureProvider(this);
1259         }
1260         return mDashboardFeatureProvider.isEnabled();
1261     }
1262
1263     // give subclasses access to the Next button
1264     public boolean hasNextButton() {
1265         return mNextButton != null;
1266     }
1267
1268     public Button getNextButton() {
1269         return mNextButton;
1270     }
1271
1272     @Override
1273     public boolean shouldUpRecreateTask(Intent targetIntent) {
1274         return super.shouldUpRecreateTask(new Intent(this, SettingsActivity.class));
1275     }
1276
1277     @Override
1278     public boolean onQueryTextSubmit(String query) {
1279         switchToSearchResultsFragmentIfNeeded();
1280         mSearchQuery = query;
1281         return mSearchResultsFragment.onQueryTextSubmit(query);
1282     }
1283
1284     @Override
1285     public boolean onQueryTextChange(String newText) {
1286         mSearchQuery = newText;
1287         if (mSearchResultsFragment == null) {
1288             return false;
1289         }
1290         return mSearchResultsFragment.onQueryTextChange(newText);
1291     }
1292
1293     @Override
1294     public boolean onClose() {
1295         return false;
1296     }
1297
1298     @Override
1299     public boolean onMenuItemActionExpand(MenuItem item) {
1300         if (item.getItemId() == mSearchMenuItem.getItemId()) {
1301             switchToSearchResultsFragmentIfNeeded();
1302         }
1303         return true;
1304     }
1305
1306     @Override
1307     public boolean onMenuItemActionCollapse(MenuItem item) {
1308         if (item.getItemId() == mSearchMenuItem.getItemId()) {
1309             if (mSearchMenuItemExpanded) {
1310                 revertToInitialFragment();
1311             }
1312         }
1313         return true;
1314     }
1315
1316     @Override
1317     protected void onTileClicked(Tile tile) {
1318         if (mIsShowingDashboard) {
1319             // If on dashboard, don't finish so the back comes back to here.
1320             openTile(tile);
1321         } else {
1322             super.onTileClicked(tile);
1323         }
1324     }
1325
1326     @Override
1327     public void onProfileTileOpen() {
1328         if (!mIsShowingDashboard) {
1329             finish();
1330         }
1331     }
1332
1333     private void switchToSearchResultsFragmentIfNeeded() {
1334         if (mSearchResultsFragment != null) {
1335             return;
1336         }
1337         Fragment current = getFragmentManager().findFragmentById(R.id.main_content);
1338         if (current != null && current instanceof SearchResultsSummary) {
1339             mSearchResultsFragment = (SearchResultsSummary) current;
1340         } else {
1341             setContentHeaderView(null);
1342             mSearchResultsFragment = (SearchResultsSummary) switchToFragment(
1343                     SearchResultsSummary.class.getName(), null, false, true,
1344                     R.string.search_results_title, null, true);
1345         }
1346         mSearchResultsFragment.setSearchView(mSearchView);
1347         mSearchMenuItemExpanded = true;
1348     }
1349
1350     public void needToRevertToInitialFragment() {
1351         mNeedToRevertToInitialFragment = true;
1352     }
1353
1354     private void revertToInitialFragment() {
1355         mNeedToRevertToInitialFragment = false;
1356         mSearchResultsFragment = null;
1357         mSearchMenuItemExpanded = false;
1358         getFragmentManager().popBackStackImmediate(SettingsActivity.BACK_STACK_PREFS,
1359                 FragmentManager.POP_BACK_STACK_INCLUSIVE);
1360         if (mSearchMenuItem != null) {
1361             mSearchMenuItem.collapseActionView();
1362         }
1363     }
1364
1365     public Intent getResultIntentData() {
1366         return mResultIntentData;
1367     }
1368
1369     public void setResultIntentData(Intent resultIntentData) {
1370         mResultIntentData = resultIntentData;
1371     }
1372
1373     public void startSuggestion(Intent intent) {
1374         if (intent == null || ActivityManager.isUserAMonkey()) {
1375             return;
1376         }
1377         mCurrentSuggestion = intent.getComponent();
1378         startActivityForResult(intent, REQUEST_SUGGESTION);
1379     }
1380
1381     @Override
1382     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
1383         if (requestCode == REQUEST_SUGGESTION && mCurrentSuggestion != null
1384                 && resultCode != RESULT_CANCELED) {
1385             getPackageManager().setComponentEnabledSetting(mCurrentSuggestion,
1386                     PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
1387         }
1388         super.onActivityResult(requestCode, resultCode, data);
1389     }
1390 }