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