2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
19 import android.app.ActionBar;
20 import android.app.Fragment;
21 import android.app.FragmentManager;
22 import android.app.FragmentTransaction;
23 import android.content.BroadcastReceiver;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.SharedPreferences;
29 import android.content.pm.ActivityInfo;
30 import android.content.pm.PackageManager;
31 import android.content.pm.PackageManager.NameNotFoundException;
32 import android.content.res.Configuration;
33 import android.nfc.NfcAdapter;
34 import android.os.AsyncTask;
35 import android.os.Bundle;
36 import android.os.UserHandle;
37 import android.os.UserManager;
38 import android.support.v14.preference.PreferenceFragment;
39 import android.support.v7.preference.Preference;
40 import android.support.v7.preference.PreferenceManager;
41 import android.text.TextUtils;
42 import android.transition.TransitionManager;
43 import android.util.Log;
44 import android.view.Menu;
45 import android.view.MenuInflater;
46 import android.view.MenuItem;
47 import android.view.View;
48 import android.view.View.OnClickListener;
49 import android.view.ViewGroup;
50 import android.widget.Button;
51 import android.widget.SearchView;
52 import com.android.internal.util.ArrayUtils;
53 import com.android.settings.Settings.WifiSettingsActivity;
54 import com.android.settings.accessibility.AccessibilitySettings;
55 import com.android.settings.accessibility.AccessibilitySettingsForSetupWizard;
56 import com.android.settings.accessibility.CaptionPropertiesFragment;
57 import com.android.settings.accounts.AccountSettings;
58 import com.android.settings.accounts.AccountSyncSettings;
59 import com.android.settings.applications.AdvancedAppSettings;
60 import com.android.settings.applications.DrawOverlayDetails;
61 import com.android.settings.applications.InstalledAppDetails;
62 import com.android.settings.applications.ManageApplications;
63 import com.android.settings.applications.ManageAssist;
64 import com.android.settings.applications.NotificationApps;
65 import com.android.settings.applications.ProcessStatsSummary;
66 import com.android.settings.applications.ProcessStatsUi;
67 import com.android.settings.applications.UsageAccessDetails;
68 import com.android.settings.applications.WriteSettingsDetails;
69 import com.android.settings.applications.VrListenerSettings;
70 import com.android.settings.bluetooth.BluetoothSettings;
71 import com.android.settings.dashboard.DashboardSummary;
72 import com.android.settings.dashboard.SearchResultsSummary;
73 import com.android.settings.datausage.DataUsageSummary;
74 import com.android.settings.deviceinfo.PrivateVolumeForget;
75 import com.android.settings.deviceinfo.PrivateVolumeSettings;
76 import com.android.settings.deviceinfo.PublicVolumeSettings;
77 import com.android.settings.deviceinfo.StorageSettings;
78 import com.android.settings.fuelgauge.BatterySaverSettings;
79 import com.android.settings.fuelgauge.PowerUsageDetail;
80 import com.android.settings.fuelgauge.PowerUsageSummary;
81 import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment;
82 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
83 import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
84 import com.android.settings.inputmethod.KeyboardLayoutPickerFragment2;
85 import com.android.settings.inputmethod.PhysicalKeyboardFragment;
86 import com.android.settings.inputmethod.SpellCheckersSettings;
87 import com.android.settings.inputmethod.UserDictionaryList;
88 import com.android.settings.localepicker.LocaleListEditor;
89 import com.android.settings.location.LocationSettings;
90 import com.android.settings.nfc.AndroidBeam;
91 import com.android.settings.nfc.PaymentSettings;
92 import com.android.settings.notification.AppNotificationSettings;
93 import com.android.settings.notification.ConfigureNotificationSettings;
94 import com.android.settings.notification.NotificationAccessSettings;
95 import com.android.settings.notification.NotificationStation;
96 import com.android.settings.notification.OtherSoundSettings;
97 import com.android.settings.notification.SoundSettings;
98 import com.android.settings.notification.ZenAccessSettings;
99 import com.android.settings.notification.ZenModeAutomationSettings;
100 import com.android.settings.notification.ZenModeEventRuleSettings;
101 import com.android.settings.notification.ZenModePrioritySettings;
102 import com.android.settings.notification.ZenModeScheduleRuleSettings;
103 import com.android.settings.notification.ZenModeSettings;
104 import com.android.settings.notification.ZenModeVisualInterruptionSettings;
105 import com.android.settings.print.PrintJobSettingsFragment;
106 import com.android.settings.print.PrintSettingsFragment;
107 import com.android.settings.search.DynamicIndexableContentMonitor;
108 import com.android.settings.search.Index;
109 import com.android.settings.sim.SimSettings;
110 import com.android.settings.tts.TextToSpeechSettings;
111 import com.android.settings.users.UserSettings;
112 import com.android.settings.vpn2.VpnSettings;
113 import com.android.settings.wfd.WifiDisplaySettings;
114 import com.android.settings.widget.SwitchBar;
115 import com.android.settings.wifi.AdvancedWifiSettings;
116 import com.android.settings.wifi.SavedAccessPointsWifiSettings;
117 import com.android.settings.wifi.WifiSettings;
118 import com.android.settings.wifi.p2p.WifiP2pSettings;
119 import com.android.settingslib.drawer.DashboardCategory;
120 import com.android.settingslib.drawer.SettingsDrawerActivity;
121 import com.android.settingslib.drawer.Tile;
123 import java.util.ArrayList;
124 import java.util.List;
125 import java.util.Set;
127 public class SettingsActivity extends SettingsDrawerActivity
128 implements PreferenceManager.OnPreferenceTreeClickListener,
129 PreferenceFragment.OnPreferenceStartFragmentCallback,
130 ButtonBarHandler, FragmentManager.OnBackStackChangedListener,
131 SearchView.OnQueryTextListener, SearchView.OnCloseListener,
132 MenuItem.OnActionExpandListener {
134 private static final String LOG_TAG = "Settings";
136 private static final int LOADER_ID_INDEXABLE_CONTENT_MONITOR = 1;
138 // Constants for state save/restore
139 private static final String SAVE_KEY_CATEGORIES = ":settings:categories";
140 private static final String SAVE_KEY_SEARCH_MENU_EXPANDED = ":settings:search_menu_expanded";
141 private static final String SAVE_KEY_SEARCH_QUERY = ":settings:search_query";
142 private static final String SAVE_KEY_SHOW_HOME_AS_UP = ":settings:show_home_as_up";
143 private static final String SAVE_KEY_SHOW_SEARCH = ":settings:show_search";
144 private static final String SAVE_KEY_HOME_ACTIVITIES_COUNT = ":settings:home_activities_count";
147 * When starting this activity, the invoking Intent can contain this extra
148 * string to specify which fragment should be initially displayed.
149 * <p/>Starting from Key Lime Pie, when this argument is passed in, the activity
150 * will call isValidFragment() to confirm that the fragment class name is valid for this
153 public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment";
156 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
157 * this extra can also be specified to supply a Bundle of arguments to pass
158 * to that fragment when it is instantiated during the initial creation
161 public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
164 * Fragment "key" argument passed thru {@link #EXTRA_SHOW_FRAGMENT_ARGUMENTS}
166 public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
168 public static final String BACK_STACK_PREFS = ":settings:prefs";
170 // extras that allow any preference activity to be launched as part of a wizard
172 // show Back and Next buttons? takes boolean parameter
173 // Back will then return RESULT_CANCELED and Next RESULT_OK
174 protected static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
176 // add a Skip button?
177 private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip";
179 // specify custom text for the Back or Next buttons, or cause a button to not appear
180 // at all by setting it to null
181 protected static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
182 protected static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
185 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
186 * those extra can also be specify to supply the title or title res id to be shown for
189 public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":settings:show_fragment_title";
191 * The package name used to resolve the title resource id.
193 public static final String EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME =
194 ":settings:show_fragment_title_res_package_name";
195 public static final String EXTRA_SHOW_FRAGMENT_TITLE_RESID =
196 ":settings:show_fragment_title_resid";
197 public static final String EXTRA_SHOW_FRAGMENT_AS_SHORTCUT =
198 ":settings:show_fragment_as_shortcut";
200 public static final String EXTRA_SHOW_FRAGMENT_AS_SUBSETTING =
201 ":settings:show_fragment_as_subsetting";
203 public static final String EXTRA_HIDE_DRAWER = ":settings:hide_drawer";
205 public static final String META_DATA_KEY_FRAGMENT_CLASS =
206 "com.android.settings.FRAGMENT_CLASS";
208 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
210 private static final String EMPTY_QUERY = "";
212 private static final int REQUEST_SUGGESTION = 42;
214 private String mFragmentClass;
216 private CharSequence mInitialTitle;
217 private int mInitialTitleResId;
219 // Show only these settings for restricted users
220 private String[] SETTINGS_FOR_RESTRICTED = {
222 WifiSettingsActivity.class.getName(),
223 Settings.BluetoothSettingsActivity.class.getName(),
224 Settings.DataUsageSummaryActivity.class.getName(),
225 Settings.SimSettingsActivity.class.getName(),
226 Settings.WirelessSettingsActivity.class.getName(),
228 Settings.HomeSettingsActivity.class.getName(),
229 Settings.SoundSettingsActivity.class.getName(),
230 Settings.DisplaySettingsActivity.class.getName(),
231 Settings.StorageSettingsActivity.class.getName(),
232 Settings.ManageApplicationsActivity.class.getName(),
233 Settings.PowerUsageSummaryActivity.class.getName(),
235 Settings.LocationSettingsActivity.class.getName(),
236 Settings.SecuritySettingsActivity.class.getName(),
237 Settings.InputMethodAndLanguageSettingsActivity.class.getName(),
238 Settings.UserSettingsActivity.class.getName(),
239 Settings.AccountSettingsActivity.class.getName(),
241 Settings.DateTimeSettingsActivity.class.getName(),
242 Settings.DeviceInfoSettingsActivity.class.getName(),
243 Settings.AccessibilitySettingsActivity.class.getName(),
244 Settings.PrintSettingsActivity.class.getName(),
245 Settings.PaymentSettingsActivity.class.getName(),
248 private static final String[] ENTRY_FRAGMENTS = {
249 WirelessSettings.class.getName(),
250 WifiSettings.class.getName(),
251 AdvancedWifiSettings.class.getName(),
252 SavedAccessPointsWifiSettings.class.getName(),
253 BluetoothSettings.class.getName(),
254 SimSettings.class.getName(),
255 TetherSettings.class.getName(),
256 WifiP2pSettings.class.getName(),
257 VpnSettings.class.getName(),
258 DateTimeSettings.class.getName(),
259 LocaleListEditor.class.getName(),
260 InputMethodAndLanguageSettings.class.getName(),
261 AvailableVirtualKeyboardFragment.class.getName(),
262 SpellCheckersSettings.class.getName(),
263 UserDictionaryList.class.getName(),
264 UserDictionarySettings.class.getName(),
265 HomeSettings.class.getName(),
266 DisplaySettings.class.getName(),
267 DeviceInfoSettings.class.getName(),
268 ManageApplications.class.getName(),
269 NotificationApps.class.getName(),
270 ManageAssist.class.getName(),
271 ProcessStatsUi.class.getName(),
272 NotificationStation.class.getName(),
273 LocationSettings.class.getName(),
274 SecuritySettings.class.getName(),
275 UsageAccessDetails.class.getName(),
276 PrivacySettings.class.getName(),
277 DeviceAdminSettings.class.getName(),
278 AccessibilitySettings.class.getName(),
279 AccessibilitySettingsForSetupWizard.class.getName(),
280 CaptionPropertiesFragment.class.getName(),
281 com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(),
282 TextToSpeechSettings.class.getName(),
283 StorageSettings.class.getName(),
284 PrivateVolumeForget.class.getName(),
285 PrivateVolumeSettings.class.getName(),
286 PublicVolumeSettings.class.getName(),
287 DevelopmentSettings.class.getName(),
288 AndroidBeam.class.getName(),
289 WifiDisplaySettings.class.getName(),
290 PowerUsageSummary.class.getName(),
291 AccountSyncSettings.class.getName(),
292 AccountSettings.class.getName(),
293 CryptKeeperSettings.class.getName(),
294 DataUsageSummary.class.getName(),
295 DreamSettings.class.getName(),
296 UserSettings.class.getName(),
297 NotificationAccessSettings.class.getName(),
298 ZenAccessSettings.class.getName(),
299 PrintSettingsFragment.class.getName(),
300 PrintJobSettingsFragment.class.getName(),
301 TrustedCredentialsSettings.class.getName(),
302 PaymentSettings.class.getName(),
303 KeyboardLayoutPickerFragment.class.getName(),
304 KeyboardLayoutPickerFragment2.class.getName(),
305 PhysicalKeyboardFragment.class.getName(),
306 ZenModeSettings.class.getName(),
307 SoundSettings.class.getName(),
308 ConfigureNotificationSettings.class.getName(),
309 ChooseLockPassword.ChooseLockPasswordFragment.class.getName(),
310 ChooseLockPattern.ChooseLockPatternFragment.class.getName(),
311 InstalledAppDetails.class.getName(),
312 BatterySaverSettings.class.getName(),
313 AppNotificationSettings.class.getName(),
314 OtherSoundSettings.class.getName(),
315 ApnSettings.class.getName(),
316 WifiCallingSettings.class.getName(),
317 ZenModePrioritySettings.class.getName(),
318 ZenModeAutomationSettings.class.getName(),
319 ZenModeScheduleRuleSettings.class.getName(),
320 ZenModeEventRuleSettings.class.getName(),
321 ZenModeVisualInterruptionSettings.class.getName(),
322 ProcessStatsUi.class.getName(),
323 PowerUsageDetail.class.getName(),
324 ProcessStatsSummary.class.getName(),
325 DrawOverlayDetails.class.getName(),
326 WriteSettingsDetails.class.getName(),
327 AdvancedAppSettings.class.getName(),
328 WallpaperTypeSettings.class.getName(),
329 VrListenerSettings.class.getName(),
333 private static final String[] LIKE_SHORTCUT_INTENT_ACTION_ARRAY = {
334 "android.settings.APPLICATION_DETAILS_SETTINGS"
337 private SharedPreferences mDevelopmentPreferences;
338 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
340 private boolean mBatteryPresent = true;
341 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
343 public void onReceive(Context context, Intent intent) {
344 String action = intent.getAction();
345 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
346 boolean batteryPresent = Utils.isBatteryPresent(intent);
348 if (mBatteryPresent != batteryPresent) {
349 mBatteryPresent = batteryPresent;
356 private final BroadcastReceiver mUserAddRemoveReceiver = new BroadcastReceiver() {
358 public void onReceive(Context context, Intent intent) {
359 String action = intent.getAction();
360 if (action.equals(Intent.ACTION_USER_ADDED)
361 || action.equals(Intent.ACTION_USER_REMOVED)) {
362 Index.getInstance(getApplicationContext()).update();
367 private final DynamicIndexableContentMonitor mDynamicIndexableContentMonitor =
368 new DynamicIndexableContentMonitor();
370 private ActionBar mActionBar;
371 private SwitchBar mSwitchBar;
373 private Button mNextButton;
375 private boolean mDisplayHomeAsUpEnabled;
376 private boolean mDisplaySearch;
378 private boolean mIsShowingDashboard;
379 private boolean mIsShortcut;
381 private int mMainContentId = R.id.main_content;
382 private ViewGroup mContent;
384 private SearchView mSearchView;
385 private MenuItem mSearchMenuItem;
386 private boolean mSearchMenuItemExpanded = false;
387 private SearchResultsSummary mSearchResultsFragment;
388 private String mSearchQuery;
391 private ArrayList<DashboardCategory> mCategories = new ArrayList<DashboardCategory>();
393 private static final String MSG_DATA_FORCE_REFRESH = "msg_data_force_refresh";
395 private boolean mNeedToRevertToInitialFragment = false;
397 private Intent mResultIntentData;
398 private ComponentName mCurrentSuggestion;
400 public SwitchBar getSwitchBar() {
405 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
406 // Override the fragment title for Wallpaper settings
407 CharSequence title = pref.getTitle();
408 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
409 title = getString(R.string.wallpaper_settings_fragment_title);
411 startPreferencePanel(pref.getFragment(), pref.getExtras(), -1, title,
417 public boolean onPreferenceTreeClick(Preference preference) {
422 public void onConfigurationChanged(Configuration newConfig) {
423 super.onConfigurationChanged(newConfig);
424 Index.getInstance(this).update();
428 protected void onStart() {
431 if (mNeedToRevertToInitialFragment) {
432 revertToInitialFragment();
437 public boolean onCreateOptionsMenu(Menu menu) {
438 if (!mDisplaySearch) {
442 MenuInflater inflater = getMenuInflater();
443 inflater.inflate(R.menu.options_menu, menu);
445 // Cache the search query (can be overriden by the OnQueryTextListener)
446 final String query = mSearchQuery;
448 mSearchMenuItem = menu.findItem(R.id.search);
449 mSearchView = (SearchView) mSearchMenuItem.getActionView();
451 if (mSearchMenuItem == null || mSearchView == null) {
455 if (mSearchResultsFragment != null) {
456 mSearchResultsFragment.setSearchView(mSearchView);
459 mSearchMenuItem.setOnActionExpandListener(this);
460 mSearchView.setOnQueryTextListener(this);
461 mSearchView.setOnCloseListener(this);
463 if (mSearchMenuItemExpanded) {
464 mSearchMenuItem.expandActionView();
466 mSearchView.setQuery(query, true /* submit */);
472 public SharedPreferences getSharedPreferences(String name, int mode) {
473 if (name.equals(getPackageName() + "_preferences")) {
474 return new SharedPreferencesLogger(this, getMetricsTag());
476 return super.getSharedPreferences(name, mode);
479 private String getMetricsTag() {
480 String tag = getClass().getName();
481 if (getIntent() != null && getIntent().hasExtra(EXTRA_SHOW_FRAGMENT)) {
482 tag = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
484 if (tag.startsWith("com.android.settings.")) {
485 tag = tag.replace("com.android.settings.", "");
490 private static boolean isShortCutIntent(final Intent intent) {
491 Set<String> categories = intent.getCategories();
492 return (categories != null) && categories.contains("com.android.settings.SHORTCUT");
495 private static boolean isLikeShortCutIntent(final Intent intent) {
496 String action = intent.getAction();
497 if (action == null) {
500 for (int i = 0; i < LIKE_SHORTCUT_INTENT_ACTION_ARRAY.length; i++) {
501 if (LIKE_SHORTCUT_INTENT_ACTION_ARRAY[i].equals(action)) return true;
507 protected void onCreate(Bundle savedState) {
508 super.onCreate(savedState);
509 long startTime = System.currentTimeMillis();
511 // Should happen before any call to getIntent()
514 final Intent intent = getIntent();
515 if (intent.hasExtra(EXTRA_UI_OPTIONS)) {
516 getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));
518 if (intent.getBooleanExtra(EXTRA_HIDE_DRAWER, false)) {
519 setIsDrawerPresent(false);
522 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
523 Context.MODE_PRIVATE);
525 // Getting Intent properties can only be done after the super.onCreate(...)
526 final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
528 mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||
529 intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);
531 final ComponentName cn = intent.getComponent();
532 final String className = cn.getClassName();
534 mIsShowingDashboard = className.equals(Settings.class.getName())
535 || className.equals(Settings.WirelessSettings.class.getName())
536 || className.equals(Settings.DeviceSettings.class.getName())
537 || className.equals(Settings.PersonalSettings.class.getName())
538 || className.equals(Settings.WirelessSettings.class.getName());
540 // This is a "Sub Settings" when:
541 // - this is a real SubSettings
542 // - or :settings:show_fragment_as_subsetting is passed to the Intent
543 final boolean isSubSettings = this instanceof SubSettings ||
544 intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);
546 // If this is a sub settings, then apply the SubSettings Theme for the ActionBar content insets
548 // Check also that we are not a Theme Dialog as we don't want to override them
549 final int themeResId = getThemeResId();
550 if (themeResId != R.style.Theme_DialogWhenLarge &&
551 themeResId != R.style.Theme_SubSettingsDialogWhenLarge) {
552 setTheme(R.style.Theme_SubSettings);
556 setContentView(mIsShowingDashboard ?
557 R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
559 mContent = (ViewGroup) findViewById(mMainContentId);
561 getFragmentManager().addOnBackStackChangedListener(this);
563 if (mIsShowingDashboard) {
564 // Run the Index update only if we have some space
565 if (!Utils.isLowStorage(this)) {
566 long indexStartTime = System.currentTimeMillis();
567 AsyncTask.execute(new Runnable() {
570 Index.getInstance(getApplicationContext()).update();
573 if (DEBUG_TIMING) Log.d(LOG_TAG, "Index.update() took "
574 + (System.currentTimeMillis() - indexStartTime) + " ms");
576 Log.w(LOG_TAG, "Cannot update the Indexer as we are running low on storage space!");
580 if (savedState != null) {
581 // We are restarting from a previous saved state; used that to initialize, instead
582 // of starting fresh.
583 mSearchMenuItemExpanded = savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED);
584 mSearchQuery = savedState.getString(SAVE_KEY_SEARCH_QUERY);
586 setTitleFromIntent(intent);
588 ArrayList<DashboardCategory> categories =
589 savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES);
590 if (categories != null) {
592 mCategories.addAll(categories);
593 setTitleFromBackStack();
596 mDisplayHomeAsUpEnabled = savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP);
597 mDisplaySearch = savedState.getBoolean(SAVE_KEY_SHOW_SEARCH);
599 if (!mIsShowingDashboard) {
600 mDisplaySearch = false;
601 // UP will be shown only if it is a sub settings
603 mDisplayHomeAsUpEnabled = isSubSettings;
604 } else if (isSubSettings) {
605 mDisplayHomeAsUpEnabled = true;
607 mDisplayHomeAsUpEnabled = false;
609 setTitleFromIntent(intent);
611 Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
612 switchToFragment(initialFragmentName, initialArguments, true, false,
613 mInitialTitleResId, mInitialTitle, false);
615 // No UP affordance if we are displaying the main Dashboard
616 mDisplayHomeAsUpEnabled = false;
617 // Show Search affordance
618 mDisplaySearch = true;
619 mInitialTitleResId = R.string.dashboard_title;
620 switchToFragment(DashboardSummary.class.getName(), null, false, false,
621 mInitialTitleResId, mInitialTitle, false);
625 mActionBar = getActionBar();
626 if (mActionBar != null) {
627 mActionBar.setDisplayHomeAsUpEnabled(mDisplayHomeAsUpEnabled);
628 mActionBar.setHomeButtonEnabled(mDisplayHomeAsUpEnabled);
630 mSwitchBar = (SwitchBar) findViewById(R.id.switch_bar);
631 if (mSwitchBar != null) {
632 mSwitchBar.setMetricsTag(getMetricsTag());
635 // see if we should show Back/Next buttons
636 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
638 View buttonBar = findViewById(R.id.button_bar);
639 if (buttonBar != null) {
640 buttonBar.setVisibility(View.VISIBLE);
642 Button backButton = (Button)findViewById(R.id.back_button);
643 backButton.setOnClickListener(new OnClickListener() {
644 public void onClick(View v) {
645 setResult(RESULT_CANCELED, getResultIntentData());
649 Button skipButton = (Button)findViewById(R.id.skip_button);
650 skipButton.setOnClickListener(new OnClickListener() {
651 public void onClick(View v) {
652 setResult(RESULT_OK, getResultIntentData());
656 mNextButton = (Button)findViewById(R.id.next_button);
657 mNextButton.setOnClickListener(new OnClickListener() {
658 public void onClick(View v) {
659 setResult(RESULT_OK, getResultIntentData());
664 // set our various button parameters
665 if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
666 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
667 if (TextUtils.isEmpty(buttonText)) {
668 mNextButton.setVisibility(View.GONE);
671 mNextButton.setText(buttonText);
674 if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
675 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
676 if (TextUtils.isEmpty(buttonText)) {
677 backButton.setVisibility(View.GONE);
680 backButton.setText(buttonText);
683 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
684 skipButton.setVisibility(View.VISIBLE);
689 if (DEBUG_TIMING) Log.d(LOG_TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
694 * Sets the id of the view continaing the main content. Should be called before calling super's
697 protected void setMainContentId(int contentId) {
698 mMainContentId = contentId;
701 private void setTitleFromIntent(Intent intent) {
702 final int initialTitleResId = intent.getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, -1);
703 if (initialTitleResId > 0) {
704 mInitialTitle = null;
705 mInitialTitleResId = initialTitleResId;
707 final String initialTitleResPackageName = intent.getStringExtra(
708 EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME);
709 if (initialTitleResPackageName != null) {
711 Context authContext = createPackageContextAsUser(initialTitleResPackageName,
712 0 /* flags */, new UserHandle(UserHandle.myUserId()));
713 mInitialTitle = authContext.getResources().getText(mInitialTitleResId);
714 setTitle(mInitialTitle);
715 mInitialTitleResId = -1;
717 } catch (NameNotFoundException e) {
718 Log.w(LOG_TAG, "Could not find package" + initialTitleResPackageName);
721 setTitle(mInitialTitleResId);
724 mInitialTitleResId = -1;
725 final String initialTitle = intent.getStringExtra(EXTRA_SHOW_FRAGMENT_TITLE);
726 mInitialTitle = (initialTitle != null) ? initialTitle : getTitle();
727 setTitle(mInitialTitle);
732 public void onBackStackChanged() {
733 setTitleFromBackStack();
736 private int setTitleFromBackStack() {
737 final int count = getFragmentManager().getBackStackEntryCount();
740 if (mInitialTitleResId > 0) {
741 setTitle(mInitialTitleResId);
743 setTitle(mInitialTitle);
748 FragmentManager.BackStackEntry bse = getFragmentManager().getBackStackEntryAt(count - 1);
749 setTitleFromBackStackEntry(bse);
754 private void setTitleFromBackStackEntry(FragmentManager.BackStackEntry bse) {
755 final CharSequence title;
756 final int titleRes = bse.getBreadCrumbTitleRes();
758 title = getText(titleRes);
760 title = bse.getBreadCrumbTitle();
768 protected void onSaveInstanceState(Bundle outState) {
769 super.onSaveInstanceState(outState);
771 if (mCategories.size() > 0) {
772 outState.putParcelableArrayList(SAVE_KEY_CATEGORIES, mCategories);
775 outState.putBoolean(SAVE_KEY_SHOW_HOME_AS_UP, mDisplayHomeAsUpEnabled);
776 outState.putBoolean(SAVE_KEY_SHOW_SEARCH, mDisplaySearch);
778 if (mDisplaySearch) {
779 // The option menus are created if the ActionBar is visible and they are also created
780 // asynchronously. If you launch Settings with an Intent action like
781 // android.intent.action.POWER_USAGE_SUMMARY and at the same time your device is locked
782 // thru a LockScreen, onCreateOptionsMenu() is not yet called and references to the search
783 // menu item and search view are null.
784 boolean isExpanded = (mSearchMenuItem != null) && mSearchMenuItem.isActionViewExpanded();
785 outState.putBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED, isExpanded);
787 String query = (mSearchView != null) ? mSearchView.getQuery().toString() : EMPTY_QUERY;
788 outState.putString(SAVE_KEY_SEARCH_QUERY, query);
793 protected void onResume() {
796 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
798 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
802 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
803 mDevelopmentPreferencesListener);
805 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
806 registerReceiver(mUserAddRemoveReceiver, new IntentFilter(Intent.ACTION_USER_ADDED));
807 registerReceiver(mUserAddRemoveReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
809 mDynamicIndexableContentMonitor.register(this, LOADER_ID_INDEXABLE_CONTENT_MONITOR);
811 if(mDisplaySearch && !TextUtils.isEmpty(mSearchQuery)) {
812 onQueryTextSubmit(mSearchQuery);
818 protected void onPause() {
820 unregisterReceiver(mBatteryInfoReceiver);
821 unregisterReceiver(mUserAddRemoveReceiver);
822 mDynamicIndexableContentMonitor.unregister();
826 public void onDestroy() {
829 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
830 mDevelopmentPreferencesListener);
831 mDevelopmentPreferencesListener = null;
834 protected boolean isValidFragment(String fragmentName) {
835 // Almost all fragments are wrapped in this,
836 // except for a few that have their own activities.
837 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
838 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
844 public Intent getIntent() {
845 Intent superIntent = super.getIntent();
846 String startingFragment = getStartingFragmentClass(superIntent);
847 // This is called from super.onCreate, isMultiPane() is not yet reliable
848 // Do not use onIsHidingHeaders either, which relies itself on this method
849 if (startingFragment != null) {
850 Intent modIntent = new Intent(superIntent);
851 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
852 Bundle args = superIntent.getExtras();
854 args = new Bundle(args);
858 args.putParcelable("intent", superIntent);
859 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
866 * Checks if the component name in the intent is different from the Settings class and
867 * returns the class name to load as a fragment.
869 private String getStartingFragmentClass(Intent intent) {
870 if (mFragmentClass != null) return mFragmentClass;
872 String intentClass = intent.getComponent().getClassName();
873 if (intentClass.equals(getClass().getName())) return null;
875 if ("com.android.settings.ManageApplications".equals(intentClass)
876 || "com.android.settings.RunningServices".equals(intentClass)
877 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
878 // Old names of manage apps.
879 intentClass = com.android.settings.applications.ManageApplications.class.getName();
886 * Start a new fragment containing a preference panel. If the preferences
887 * are being displayed in multi-pane mode, the given fragment class will
888 * be instantiated and placed in the appropriate pane. If running in
889 * single-pane mode, a new activity will be launched in which to show the
892 * @param fragmentClass Full name of the class implementing the fragment.
893 * @param args Any desired arguments to supply to the fragment.
894 * @param titleRes Optional resource identifier of the title of this
896 * @param titleText Optional text of the title of this fragment.
897 * @param resultTo Optional fragment that result data should be sent to.
898 * If non-null, resultTo.onActivityResult() will be called when this
899 * preference panel is done. The launched panel must use
900 * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
901 * @param resultRequestCode If resultTo is non-null, this is the caller's
902 * request code to be received with the result.
904 public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
905 CharSequence titleText, Fragment resultTo, int resultRequestCode) {
908 if (titleText != null) {
909 title = titleText.toString();
911 // There not much we can do in that case
915 Utils.startWithFragment(this, fragmentClass, args, resultTo, resultRequestCode,
916 titleRes, title, mIsShortcut);
920 * Start a new fragment in a new activity containing a preference panel for a given user. If the
921 * preferences are being displayed in multi-pane mode, the given fragment class will be
922 * instantiated and placed in the appropriate pane. If running in single-pane mode, a new
923 * activity will be launched in which to show the fragment.
925 * @param fragmentClass Full name of the class implementing the fragment.
926 * @param args Any desired arguments to supply to the fragment.
927 * @param titleRes Optional resource identifier of the title of this fragment.
928 * @param titleText Optional text of the title of this fragment.
929 * @param userHandle The user for which the panel has to be started.
931 public void startPreferencePanelAsUser(String fragmentClass, Bundle args, int titleRes,
932 CharSequence titleText, UserHandle userHandle) {
933 // This is a workaround.
935 // Calling startWithFragmentAsUser() without specifying FLAG_ACTIVITY_NEW_TASK to the intent
936 // starting the fragment could cause a native stack corruption. See b/17523189. However,
937 // adding that flag and start the preference panel with the same UserHandler will make it
938 // impossible to use back button to return to the previous screen. See b/20042570.
940 // We work around this issue by adding FLAG_ACTIVITY_NEW_TASK to the intent, while doing
941 // another check here to call startPreferencePanel() instead of startWithFragmentAsUser()
942 // when we're calling it as the same user.
943 if (userHandle.getIdentifier() == UserHandle.myUserId()) {
944 startPreferencePanel(fragmentClass, args, titleRes, titleText, null, 0);
948 if (titleText != null) {
949 title = titleText.toString();
951 // There not much we can do in that case
955 Utils.startWithFragmentAsUser(this, fragmentClass, args,
956 titleRes, title, mIsShortcut, userHandle);
961 * Called by a preference panel fragment to finish itself.
963 * @param caller The fragment that is asking to be finished.
964 * @param resultCode Optional result code to send back to the original
965 * launching fragment.
966 * @param resultData Optional result data to send back to the original
967 * launching fragment.
969 public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
970 setResult(resultCode, resultData);
975 * Start a new fragment.
977 * @param fragment The fragment to start
978 * @param push If true, the current fragment will be pushed onto the back stack. If false,
979 * the current fragment will be replaced.
981 public void startPreferenceFragment(Fragment fragment, boolean push) {
982 FragmentTransaction transaction = getFragmentManager().beginTransaction();
983 transaction.replace(mMainContentId, fragment);
985 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
986 transaction.addToBackStack(BACK_STACK_PREFS);
988 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
990 transaction.commitAllowingStateLoss();
994 * Switch to a specific Fragment with taking care of validation, Title and BackStack
996 private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate,
997 boolean addToBackStack, int titleResId, CharSequence title, boolean withTransition) {
998 if (validate && !isValidFragment(fragmentName)) {
999 throw new IllegalArgumentException("Invalid fragment for this activity: "
1002 Fragment f = Fragment.instantiate(this, fragmentName, args);
1003 FragmentTransaction transaction = getFragmentManager().beginTransaction();
1004 transaction.replace(mMainContentId, f);
1005 if (withTransition) {
1006 TransitionManager.beginDelayedTransition(mContent);
1008 if (addToBackStack) {
1009 transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS);
1011 if (titleResId > 0) {
1012 transaction.setBreadCrumbTitle(titleResId);
1013 } else if (title != null) {
1014 transaction.setBreadCrumbTitle(title);
1016 transaction.commitAllowingStateLoss();
1017 getFragmentManager().executePendingTransactions();
1021 private void updateTilesList() {
1022 // Generally the items that are will be changing from these updates will
1023 // not be in the top list of tiles, so run it in the background and the
1024 // SettingsDrawerActivity will pick up on the updates automatically.
1025 AsyncTask.execute(new Runnable() {
1028 doUpdateTilesList();
1033 private void doUpdateTilesList() {
1034 PackageManager pm = getPackageManager();
1035 final UserManager um = UserManager.get(this);
1036 final boolean isAdmin = um.isAdminUser();
1038 String packageName = getPackageName();
1039 setTileEnabled(new ComponentName(packageName, WifiSettingsActivity.class.getName()),
1040 pm.hasSystemFeature(PackageManager.FEATURE_WIFI), isAdmin, pm);
1042 setTileEnabled(new ComponentName(packageName,
1043 Settings.BluetoothSettingsActivity.class.getName()),
1044 pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH), isAdmin, pm);
1046 setTileEnabled(new ComponentName(packageName,
1047 Settings.DataUsageSummaryActivity.class.getName()),
1048 Utils.isBandwidthControlEnabled(), isAdmin, pm);
1050 setTileEnabled(new ComponentName(packageName,
1051 Settings.SimSettingsActivity.class.getName()),
1052 Utils.showSimCardTile(this), isAdmin, pm);
1054 setTileEnabled(new ComponentName(packageName,
1055 Settings.PowerUsageSummaryActivity.class.getName()),
1056 mBatteryPresent, isAdmin, pm);
1058 setTileEnabled(new ComponentName(packageName,
1059 Settings.UserSettingsActivity.class.getName()),
1060 UserHandle.MU_ENABLED && UserManager.supportsMultipleUsers()
1061 && !Utils.isMonkeyRunning(), isAdmin, pm);
1063 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
1064 setTileEnabled(new ComponentName(packageName,
1065 Settings.PaymentSettingsActivity.class.getName()),
1066 pm.hasSystemFeature(PackageManager.FEATURE_NFC)
1067 && pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
1068 && adapter != null && adapter.isEnabled(), isAdmin, pm);
1070 setTileEnabled(new ComponentName(packageName,
1071 Settings.PrintSettingsActivity.class.getName()),
1072 pm.hasSystemFeature(PackageManager.FEATURE_PRINTING), isAdmin, pm);
1074 final boolean showDev = mDevelopmentPreferences.getBoolean(
1075 DevelopmentSettings.PREF_SHOW,
1076 android.os.Build.TYPE.equals("eng"));
1077 setTileEnabled(new ComponentName(packageName,
1078 Settings.DevelopmentSettingsActivity.class.getName()),
1079 showDev && !um.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES),
1082 if (UserHandle.MU_ENABLED && !isAdmin) {
1083 // When on restricted users, disable all extra categories (but only the settings ones).
1084 List<DashboardCategory> categories = getDashboardCategories();
1085 for (DashboardCategory category : categories) {
1086 for (Tile tile : category.tiles) {
1087 ComponentName component = tile.intent.getComponent();
1088 if (packageName.equals(component)&& !ArrayUtils.contains(
1089 SETTINGS_FOR_RESTRICTED, component.getClassName())) {
1090 setTileEnabled(component, false, isAdmin, pm);
1097 private void setTileEnabled(ComponentName component, boolean enabled, boolean isAdmin,
1098 PackageManager pm) {
1099 if (UserHandle.MU_ENABLED && !isAdmin
1100 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, component.getClassName())) {
1103 int state = pm.getComponentEnabledSetting(component);
1104 boolean isEnabled = state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
1105 || state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
1106 if (isEnabled != enabled) {
1107 pm.setComponentEnabledSetting(component, enabled
1108 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1109 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
1110 PackageManager.DONT_KILL_APP);
1114 private void getMetaData() {
1116 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
1117 PackageManager.GET_META_DATA);
1118 if (ai == null || ai.metaData == null) return;
1119 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
1120 } catch (NameNotFoundException nnfe) {
1122 Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());
1126 // give subclasses access to the Next button
1127 public boolean hasNextButton() {
1128 return mNextButton != null;
1131 public Button getNextButton() {
1136 public boolean shouldUpRecreateTask(Intent targetIntent) {
1137 return super.shouldUpRecreateTask(new Intent(this, SettingsActivity.class));
1141 public boolean onQueryTextSubmit(String query) {
1142 switchToSearchResultsFragmentIfNeeded();
1143 mSearchQuery = query;
1144 return mSearchResultsFragment.onQueryTextSubmit(query);
1148 public boolean onQueryTextChange(String newText) {
1149 mSearchQuery = newText;
1150 if (mSearchResultsFragment == null) {
1153 return mSearchResultsFragment.onQueryTextChange(newText);
1157 public boolean onClose() {
1162 public boolean onMenuItemActionExpand(MenuItem item) {
1163 if (item.getItemId() == mSearchMenuItem.getItemId()) {
1164 switchToSearchResultsFragmentIfNeeded();
1170 public boolean onMenuItemActionCollapse(MenuItem item) {
1171 if (item.getItemId() == mSearchMenuItem.getItemId()) {
1172 if (mSearchMenuItemExpanded) {
1173 revertToInitialFragment();
1180 protected void onTileClicked(Tile tile) {
1181 if (mIsShowingDashboard) {
1182 // If on dashboard, don't finish so the back comes back to here.
1185 super.onTileClicked(tile);
1190 public void onProfileTileOpen() {
1191 if (!mIsShowingDashboard) {
1196 private void switchToSearchResultsFragmentIfNeeded() {
1197 if (mSearchResultsFragment != null) {
1200 Fragment current = getFragmentManager().findFragmentById(mMainContentId);
1201 if (current != null && current instanceof SearchResultsSummary) {
1202 mSearchResultsFragment = (SearchResultsSummary) current;
1204 mSearchResultsFragment = (SearchResultsSummary) switchToFragment(
1205 SearchResultsSummary.class.getName(), null, false, true,
1206 R.string.search_results_title, null, true);
1208 mSearchResultsFragment.setSearchView(mSearchView);
1209 mSearchMenuItemExpanded = true;
1212 public void needToRevertToInitialFragment() {
1213 mNeedToRevertToInitialFragment = true;
1216 private void revertToInitialFragment() {
1217 mNeedToRevertToInitialFragment = false;
1218 mSearchResultsFragment = null;
1219 mSearchMenuItemExpanded = false;
1220 getFragmentManager().popBackStackImmediate(SettingsActivity.BACK_STACK_PREFS,
1221 FragmentManager.POP_BACK_STACK_INCLUSIVE);
1222 if (mSearchMenuItem != null) {
1223 mSearchMenuItem.collapseActionView();
1227 public Intent getResultIntentData() {
1228 return mResultIntentData;
1231 public void setResultIntentData(Intent resultIntentData) {
1232 mResultIntentData = resultIntentData;
1235 public void startSuggestion(Intent intent) {
1236 mCurrentSuggestion = intent.getComponent();
1237 startActivityForResult(intent, REQUEST_SUGGESTION);
1241 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
1242 if (requestCode == REQUEST_SUGGESTION && mCurrentSuggestion != null
1243 && resultCode != RESULT_CANCELED) {
1244 getPackageManager().setComponentEnabledSetting(mCurrentSuggestion,
1245 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
1247 super.onActivityResult(requestCode, resultCode, data);