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