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.accounts.ManagedProfileSettings;
60 import com.android.settings.applications.AdvancedAppSettings;
61 import com.android.settings.applications.DrawOverlayDetails;
62 import com.android.settings.applications.InstalledAppDetails;
63 import com.android.settings.applications.ManageApplications;
64 import com.android.settings.applications.ManageAssist;
65 import com.android.settings.applications.NotificationApps;
66 import com.android.settings.applications.ProcessStatsSummary;
67 import com.android.settings.applications.ProcessStatsUi;
68 import com.android.settings.applications.UsageAccessDetails;
69 import com.android.settings.applications.WriteSettingsDetails;
70 import com.android.settings.applications.VrListenerSettings;
71 import com.android.settings.bluetooth.BluetoothSettings;
72 import com.android.settings.dashboard.DashboardSummary;
73 import com.android.settings.dashboard.SearchResultsSummary;
74 import com.android.settings.datausage.DataUsageSummary;
75 import com.android.settings.deviceinfo.PrivateVolumeForget;
76 import com.android.settings.deviceinfo.PrivateVolumeSettings;
77 import com.android.settings.deviceinfo.PublicVolumeSettings;
78 import com.android.settings.deviceinfo.StorageSettings;
79 import com.android.settings.fuelgauge.BatterySaverSettings;
80 import com.android.settings.fuelgauge.PowerUsageDetail;
81 import com.android.settings.fuelgauge.PowerUsageSummary;
82 import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment;
83 import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
84 import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
85 import com.android.settings.inputmethod.KeyboardLayoutPickerFragment2;
86 import com.android.settings.inputmethod.PhysicalKeyboardFragment;
87 import com.android.settings.inputmethod.SpellCheckersSettings;
88 import com.android.settings.inputmethod.UserDictionaryList;
89 import com.android.settings.localepicker.LocaleListEditor;
90 import com.android.settings.location.LocationSettings;
91 import com.android.settings.nfc.AndroidBeam;
92 import com.android.settings.nfc.PaymentSettings;
93 import com.android.settings.notification.AppNotificationSettings;
94 import com.android.settings.notification.ConfigureNotificationSettings;
95 import com.android.settings.notification.NotificationAccessSettings;
96 import com.android.settings.notification.NotificationStation;
97 import com.android.settings.notification.OtherSoundSettings;
98 import com.android.settings.notification.SoundSettings;
99 import com.android.settings.notification.ZenAccessSettings;
100 import com.android.settings.notification.ZenModeAutomationSettings;
101 import com.android.settings.notification.ZenModeEventRuleSettings;
102 import com.android.settings.notification.ZenModePrioritySettings;
103 import com.android.settings.notification.ZenModeScheduleRuleSettings;
104 import com.android.settings.notification.ZenModeSettings;
105 import com.android.settings.notification.ZenModeVisualInterruptionSettings;
106 import com.android.settings.print.PrintJobSettingsFragment;
107 import com.android.settings.print.PrintSettingsFragment;
108 import com.android.settings.qstile.DevelopmentTiles;
109 import com.android.settings.search.DynamicIndexableContentMonitor;
110 import com.android.settings.search.Index;
111 import com.android.settings.sim.SimSettings;
112 import com.android.settings.tts.TextToSpeechSettings;
113 import com.android.settings.users.UserSettings;
114 import com.android.settings.vpn2.VpnSettings;
115 import com.android.settings.wfd.WifiDisplaySettings;
116 import com.android.settings.widget.SwitchBar;
117 import com.android.settings.wifi.AdvancedWifiSettings;
118 import com.android.settings.wifi.SavedAccessPointsWifiSettings;
119 import com.android.settings.wifi.WifiSettings;
120 import com.android.settings.wifi.p2p.WifiP2pSettings;
121 import com.android.settingslib.drawer.DashboardCategory;
122 import com.android.settingslib.drawer.SettingsDrawerActivity;
123 import com.android.settingslib.drawer.Tile;
125 import java.util.ArrayList;
126 import java.util.List;
127 import java.util.Set;
129 public class SettingsActivity extends SettingsDrawerActivity
130 implements PreferenceManager.OnPreferenceTreeClickListener,
131 PreferenceFragment.OnPreferenceStartFragmentCallback,
132 ButtonBarHandler, FragmentManager.OnBackStackChangedListener,
133 SearchView.OnQueryTextListener, SearchView.OnCloseListener,
134 MenuItem.OnActionExpandListener {
136 private static final String LOG_TAG = "Settings";
138 private static final int LOADER_ID_INDEXABLE_CONTENT_MONITOR = 1;
140 // Constants for state save/restore
141 private static final String SAVE_KEY_CATEGORIES = ":settings:categories";
142 private static final String SAVE_KEY_SEARCH_MENU_EXPANDED = ":settings:search_menu_expanded";
143 private static final String SAVE_KEY_SEARCH_QUERY = ":settings:search_query";
144 private static final String SAVE_KEY_SHOW_HOME_AS_UP = ":settings:show_home_as_up";
145 private static final String SAVE_KEY_SHOW_SEARCH = ":settings:show_search";
146 private static final String SAVE_KEY_HOME_ACTIVITIES_COUNT = ":settings:home_activities_count";
149 * When starting this activity, the invoking Intent can contain this extra
150 * string to specify which fragment should be initially displayed.
151 * <p/>Starting from Key Lime Pie, when this argument is passed in, the activity
152 * will call isValidFragment() to confirm that the fragment class name is valid for this
155 public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment";
158 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
159 * this extra can also be specified to supply a Bundle of arguments to pass
160 * to that fragment when it is instantiated during the initial creation
163 public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
166 * Fragment "key" argument passed thru {@link #EXTRA_SHOW_FRAGMENT_ARGUMENTS}
168 public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
170 public static final String BACK_STACK_PREFS = ":settings:prefs";
172 // extras that allow any preference activity to be launched as part of a wizard
174 // show Back and Next buttons? takes boolean parameter
175 // Back will then return RESULT_CANCELED and Next RESULT_OK
176 protected static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
178 // add a Skip button?
179 private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip";
181 // specify custom text for the Back or Next buttons, or cause a button to not appear
182 // at all by setting it to null
183 protected static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
184 protected static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text";
187 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT},
188 * those extra can also be specify to supply the title or title res id to be shown for
191 public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":settings:show_fragment_title";
193 * The package name used to resolve the title resource id.
195 public static final String EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME =
196 ":settings:show_fragment_title_res_package_name";
197 public static final String EXTRA_SHOW_FRAGMENT_TITLE_RESID =
198 ":settings:show_fragment_title_resid";
199 public static final String EXTRA_SHOW_FRAGMENT_AS_SHORTCUT =
200 ":settings:show_fragment_as_shortcut";
202 public static final String EXTRA_SHOW_FRAGMENT_AS_SUBSETTING =
203 ":settings:show_fragment_as_subsetting";
205 public static final String EXTRA_HIDE_DRAWER = ":settings:hide_drawer";
207 public static final String META_DATA_KEY_FRAGMENT_CLASS =
208 "com.android.settings.FRAGMENT_CLASS";
210 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
212 private static final String EMPTY_QUERY = "";
214 private static final int REQUEST_SUGGESTION = 42;
216 private String mFragmentClass;
218 private CharSequence mInitialTitle;
219 private int mInitialTitleResId;
221 // Show only these settings for restricted users
222 private String[] SETTINGS_FOR_RESTRICTED = {
224 WifiSettingsActivity.class.getName(),
225 Settings.BluetoothSettingsActivity.class.getName(),
226 Settings.DataUsageSummaryActivity.class.getName(),
227 Settings.SimSettingsActivity.class.getName(),
228 Settings.WirelessSettingsActivity.class.getName(),
230 Settings.HomeSettingsActivity.class.getName(),
231 Settings.SoundSettingsActivity.class.getName(),
232 Settings.DisplaySettingsActivity.class.getName(),
233 Settings.StorageSettingsActivity.class.getName(),
234 Settings.ManageApplicationsActivity.class.getName(),
235 Settings.PowerUsageSummaryActivity.class.getName(),
237 Settings.LocationSettingsActivity.class.getName(),
238 Settings.SecuritySettingsActivity.class.getName(),
239 Settings.InputMethodAndLanguageSettingsActivity.class.getName(),
240 Settings.UserSettingsActivity.class.getName(),
241 Settings.AccountSettingsActivity.class.getName(),
243 Settings.DateTimeSettingsActivity.class.getName(),
244 Settings.DeviceInfoSettingsActivity.class.getName(),
245 Settings.AccessibilitySettingsActivity.class.getName(),
246 Settings.PrintSettingsActivity.class.getName(),
247 Settings.PaymentSettingsActivity.class.getName(),
250 private static final String[] ENTRY_FRAGMENTS = {
251 WirelessSettings.class.getName(),
252 WifiSettings.class.getName(),
253 AdvancedWifiSettings.class.getName(),
254 SavedAccessPointsWifiSettings.class.getName(),
255 BluetoothSettings.class.getName(),
256 SimSettings.class.getName(),
257 TetherSettings.class.getName(),
258 WifiP2pSettings.class.getName(),
259 VpnSettings.class.getName(),
260 DateTimeSettings.class.getName(),
261 LocaleListEditor.class.getName(),
262 InputMethodAndLanguageSettings.class.getName(),
263 AvailableVirtualKeyboardFragment.class.getName(),
264 SpellCheckersSettings.class.getName(),
265 UserDictionaryList.class.getName(),
266 UserDictionarySettings.class.getName(),
267 HomeSettings.class.getName(),
268 DisplaySettings.class.getName(),
269 DeviceInfoSettings.class.getName(),
270 ManageApplications.class.getName(),
271 NotificationApps.class.getName(),
272 ManageAssist.class.getName(),
273 ProcessStatsUi.class.getName(),
274 NotificationStation.class.getName(),
275 LocationSettings.class.getName(),
276 SecuritySettings.class.getName(),
277 UsageAccessDetails.class.getName(),
278 PrivacySettings.class.getName(),
279 DeviceAdminSettings.class.getName(),
280 AccessibilitySettings.class.getName(),
281 AccessibilitySettingsForSetupWizard.class.getName(),
282 CaptionPropertiesFragment.class.getName(),
283 com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(),
284 TextToSpeechSettings.class.getName(),
285 StorageSettings.class.getName(),
286 PrivateVolumeForget.class.getName(),
287 PrivateVolumeSettings.class.getName(),
288 PublicVolumeSettings.class.getName(),
289 DevelopmentSettings.class.getName(),
290 AndroidBeam.class.getName(),
291 WifiDisplaySettings.class.getName(),
292 PowerUsageSummary.class.getName(),
293 AccountSyncSettings.class.getName(),
294 AccountSettings.class.getName(),
295 CryptKeeperSettings.class.getName(),
296 DataUsageSummary.class.getName(),
297 DreamSettings.class.getName(),
298 UserSettings.class.getName(),
299 NotificationAccessSettings.class.getName(),
300 ZenAccessSettings.class.getName(),
301 PrintSettingsFragment.class.getName(),
302 PrintJobSettingsFragment.class.getName(),
303 TrustedCredentialsSettings.class.getName(),
304 PaymentSettings.class.getName(),
305 KeyboardLayoutPickerFragment.class.getName(),
306 KeyboardLayoutPickerFragment2.class.getName(),
307 PhysicalKeyboardFragment.class.getName(),
308 ZenModeSettings.class.getName(),
309 SoundSettings.class.getName(),
310 ConfigureNotificationSettings.class.getName(),
311 ChooseLockPassword.ChooseLockPasswordFragment.class.getName(),
312 ChooseLockPattern.ChooseLockPatternFragment.class.getName(),
313 InstalledAppDetails.class.getName(),
314 BatterySaverSettings.class.getName(),
315 AppNotificationSettings.class.getName(),
316 OtherSoundSettings.class.getName(),
317 ApnSettings.class.getName(),
318 WifiCallingSettings.class.getName(),
319 ZenModePrioritySettings.class.getName(),
320 ZenModeAutomationSettings.class.getName(),
321 ZenModeScheduleRuleSettings.class.getName(),
322 ZenModeEventRuleSettings.class.getName(),
323 ZenModeVisualInterruptionSettings.class.getName(),
324 ProcessStatsUi.class.getName(),
325 PowerUsageDetail.class.getName(),
326 ProcessStatsSummary.class.getName(),
327 DrawOverlayDetails.class.getName(),
328 WriteSettingsDetails.class.getName(),
329 AdvancedAppSettings.class.getName(),
330 WallpaperTypeSettings.class.getName(),
331 VrListenerSettings.class.getName(),
332 ManagedProfileSettings.class.getName(),
336 private static final String[] LIKE_SHORTCUT_INTENT_ACTION_ARRAY = {
337 "android.settings.APPLICATION_DETAILS_SETTINGS"
340 private SharedPreferences mDevelopmentPreferences;
341 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
343 private boolean mBatteryPresent = true;
344 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
346 public void onReceive(Context context, Intent intent) {
347 String action = intent.getAction();
348 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
349 boolean batteryPresent = Utils.isBatteryPresent(intent);
351 if (mBatteryPresent != batteryPresent) {
352 mBatteryPresent = batteryPresent;
359 private final BroadcastReceiver mUserAddRemoveReceiver = new BroadcastReceiver() {
361 public void onReceive(Context context, Intent intent) {
362 String action = intent.getAction();
363 if (action.equals(Intent.ACTION_USER_ADDED)
364 || action.equals(Intent.ACTION_USER_REMOVED)) {
365 Index.getInstance(getApplicationContext()).update();
370 private final DynamicIndexableContentMonitor mDynamicIndexableContentMonitor =
371 new DynamicIndexableContentMonitor();
373 private ActionBar mActionBar;
374 private SwitchBar mSwitchBar;
376 private Button mNextButton;
378 private boolean mDisplayHomeAsUpEnabled;
379 private boolean mDisplaySearch;
381 private boolean mIsShowingDashboard;
382 private boolean mIsShortcut;
384 private int mMainContentId = R.id.main_content;
385 private ViewGroup mContent;
387 private SearchView mSearchView;
388 private MenuItem mSearchMenuItem;
389 private boolean mSearchMenuItemExpanded = false;
390 private SearchResultsSummary mSearchResultsFragment;
391 private String mSearchQuery;
394 private ArrayList<DashboardCategory> mCategories = new ArrayList<DashboardCategory>();
396 private static final String MSG_DATA_FORCE_REFRESH = "msg_data_force_refresh";
398 private boolean mNeedToRevertToInitialFragment = false;
400 private Intent mResultIntentData;
401 private ComponentName mCurrentSuggestion;
403 public SwitchBar getSwitchBar() {
408 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
409 // Override the fragment title for Wallpaper settings
410 CharSequence title = pref.getTitle();
411 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
412 title = getString(R.string.wallpaper_settings_fragment_title);
414 startPreferencePanel(pref.getFragment(), pref.getExtras(), -1, title,
420 public boolean onPreferenceTreeClick(Preference preference) {
425 public void onConfigurationChanged(Configuration newConfig) {
426 super.onConfigurationChanged(newConfig);
427 Index.getInstance(this).update();
431 protected void onStart() {
434 if (mNeedToRevertToInitialFragment) {
435 revertToInitialFragment();
440 public boolean onCreateOptionsMenu(Menu menu) {
441 if (!mDisplaySearch) {
445 MenuInflater inflater = getMenuInflater();
446 inflater.inflate(R.menu.options_menu, menu);
448 // Cache the search query (can be overriden by the OnQueryTextListener)
449 final String query = mSearchQuery;
451 mSearchMenuItem = menu.findItem(R.id.search);
452 mSearchView = (SearchView) mSearchMenuItem.getActionView();
454 if (mSearchMenuItem == null || mSearchView == null) {
458 if (mSearchResultsFragment != null) {
459 mSearchResultsFragment.setSearchView(mSearchView);
462 mSearchMenuItem.setOnActionExpandListener(this);
463 mSearchView.setOnQueryTextListener(this);
464 mSearchView.setOnCloseListener(this);
466 if (mSearchMenuItemExpanded) {
467 mSearchMenuItem.expandActionView();
469 mSearchView.setQuery(query, true /* submit */);
475 public SharedPreferences getSharedPreferences(String name, int mode) {
476 if (name.equals(getPackageName() + "_preferences")) {
477 return new SharedPreferencesLogger(this, getMetricsTag());
479 return super.getSharedPreferences(name, mode);
482 private String getMetricsTag() {
483 String tag = getClass().getName();
484 if (getIntent() != null && getIntent().hasExtra(EXTRA_SHOW_FRAGMENT)) {
485 tag = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
487 if (tag.startsWith("com.android.settings.")) {
488 tag = tag.replace("com.android.settings.", "");
493 private static boolean isShortCutIntent(final Intent intent) {
494 Set<String> categories = intent.getCategories();
495 return (categories != null) && categories.contains("com.android.settings.SHORTCUT");
498 private static boolean isLikeShortCutIntent(final Intent intent) {
499 String action = intent.getAction();
500 if (action == null) {
503 for (int i = 0; i < LIKE_SHORTCUT_INTENT_ACTION_ARRAY.length; i++) {
504 if (LIKE_SHORTCUT_INTENT_ACTION_ARRAY[i].equals(action)) return true;
510 protected void onCreate(Bundle savedState) {
511 super.onCreate(savedState);
512 long startTime = System.currentTimeMillis();
514 // Should happen before any call to getIntent()
517 final Intent intent = getIntent();
518 if (intent.hasExtra(EXTRA_UI_OPTIONS)) {
519 getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));
521 if (intent.getBooleanExtra(EXTRA_HIDE_DRAWER, false)) {
522 setIsDrawerPresent(false);
525 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
526 Context.MODE_PRIVATE);
528 // Getting Intent properties can only be done after the super.onCreate(...)
529 final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
531 mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||
532 intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);
534 final ComponentName cn = intent.getComponent();
535 final String className = cn.getClassName();
537 mIsShowingDashboard = className.equals(Settings.class.getName())
538 || className.equals(Settings.WirelessSettings.class.getName())
539 || className.equals(Settings.DeviceSettings.class.getName())
540 || className.equals(Settings.PersonalSettings.class.getName())
541 || className.equals(Settings.WirelessSettings.class.getName());
543 // This is a "Sub Settings" when:
544 // - this is a real SubSettings
545 // - or :settings:show_fragment_as_subsetting is passed to the Intent
546 final boolean isSubSettings = this instanceof SubSettings ||
547 intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);
549 // If this is a sub settings, then apply the SubSettings Theme for the ActionBar content insets
551 // Check also that we are not a Theme Dialog as we don't want to override them
552 final int themeResId = getThemeResId();
553 if (themeResId != R.style.Theme_DialogWhenLarge &&
554 themeResId != R.style.Theme_SubSettingsDialogWhenLarge) {
555 setTheme(R.style.Theme_SubSettings);
559 setContentView(mIsShowingDashboard ?
560 R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
562 mContent = (ViewGroup) findViewById(mMainContentId);
564 getFragmentManager().addOnBackStackChangedListener(this);
566 if (mIsShowingDashboard) {
567 // Run the Index update only if we have some space
568 if (!Utils.isLowStorage(this)) {
569 long indexStartTime = System.currentTimeMillis();
570 Index.getInstance(getApplicationContext()).update();
571 if (DEBUG_TIMING) Log.d(LOG_TAG, "Index.update() took "
572 + (System.currentTimeMillis() - indexStartTime) + " ms");
574 Log.w(LOG_TAG, "Cannot update the Indexer as we are running low on storage space!");
578 if (savedState != null) {
579 // We are restarting from a previous saved state; used that to initialize, instead
580 // of starting fresh.
581 mSearchMenuItemExpanded = savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED);
582 mSearchQuery = savedState.getString(SAVE_KEY_SEARCH_QUERY);
584 setTitleFromIntent(intent);
586 ArrayList<DashboardCategory> categories =
587 savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES);
588 if (categories != null) {
590 mCategories.addAll(categories);
591 setTitleFromBackStack();
594 mDisplayHomeAsUpEnabled = savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP);
595 mDisplaySearch = savedState.getBoolean(SAVE_KEY_SHOW_SEARCH);
597 if (!mIsShowingDashboard) {
598 mDisplaySearch = false;
599 // UP will be shown only if it is a sub settings
601 mDisplayHomeAsUpEnabled = isSubSettings;
602 } else if (isSubSettings) {
603 mDisplayHomeAsUpEnabled = true;
605 mDisplayHomeAsUpEnabled = false;
607 setTitleFromIntent(intent);
609 Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
610 switchToFragment(initialFragmentName, initialArguments, true, false,
611 mInitialTitleResId, mInitialTitle, false);
613 // No UP affordance if we are displaying the main Dashboard
614 mDisplayHomeAsUpEnabled = false;
615 // Show Search affordance
616 mDisplaySearch = true;
617 mInitialTitleResId = R.string.dashboard_title;
618 switchToFragment(DashboardSummary.class.getName(), null, false, false,
619 mInitialTitleResId, mInitialTitle, false);
623 mActionBar = getActionBar();
624 if (mActionBar != null) {
625 mActionBar.setDisplayHomeAsUpEnabled(mDisplayHomeAsUpEnabled);
626 mActionBar.setHomeButtonEnabled(mDisplayHomeAsUpEnabled);
628 mSwitchBar = (SwitchBar) findViewById(R.id.switch_bar);
629 if (mSwitchBar != null) {
630 mSwitchBar.setMetricsTag(getMetricsTag());
633 // see if we should show Back/Next buttons
634 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
636 View buttonBar = findViewById(R.id.button_bar);
637 if (buttonBar != null) {
638 buttonBar.setVisibility(View.VISIBLE);
640 Button backButton = (Button)findViewById(R.id.back_button);
641 backButton.setOnClickListener(new OnClickListener() {
642 public void onClick(View v) {
643 setResult(RESULT_CANCELED, getResultIntentData());
647 Button skipButton = (Button)findViewById(R.id.skip_button);
648 skipButton.setOnClickListener(new OnClickListener() {
649 public void onClick(View v) {
650 setResult(RESULT_OK, getResultIntentData());
654 mNextButton = (Button)findViewById(R.id.next_button);
655 mNextButton.setOnClickListener(new OnClickListener() {
656 public void onClick(View v) {
657 setResult(RESULT_OK, getResultIntentData());
662 // set our various button parameters
663 if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) {
664 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT);
665 if (TextUtils.isEmpty(buttonText)) {
666 mNextButton.setVisibility(View.GONE);
669 mNextButton.setText(buttonText);
672 if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) {
673 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT);
674 if (TextUtils.isEmpty(buttonText)) {
675 backButton.setVisibility(View.GONE);
678 backButton.setText(buttonText);
681 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
682 skipButton.setVisibility(View.VISIBLE);
687 if (DEBUG_TIMING) Log.d(LOG_TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
692 * Sets the id of the view continaing the main content. Should be called before calling super's
695 protected void setMainContentId(int contentId) {
696 mMainContentId = contentId;
699 private void setTitleFromIntent(Intent intent) {
700 final int initialTitleResId = intent.getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, -1);
701 if (initialTitleResId > 0) {
702 mInitialTitle = null;
703 mInitialTitleResId = initialTitleResId;
705 final String initialTitleResPackageName = intent.getStringExtra(
706 EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME);
707 if (initialTitleResPackageName != null) {
709 Context authContext = createPackageContextAsUser(initialTitleResPackageName,
710 0 /* flags */, new UserHandle(UserHandle.myUserId()));
711 mInitialTitle = authContext.getResources().getText(mInitialTitleResId);
712 setTitle(mInitialTitle);
713 mInitialTitleResId = -1;
715 } catch (NameNotFoundException e) {
716 Log.w(LOG_TAG, "Could not find package" + initialTitleResPackageName);
719 setTitle(mInitialTitleResId);
722 mInitialTitleResId = -1;
723 final String initialTitle = intent.getStringExtra(EXTRA_SHOW_FRAGMENT_TITLE);
724 mInitialTitle = (initialTitle != null) ? initialTitle : getTitle();
725 setTitle(mInitialTitle);
730 public void onBackStackChanged() {
731 setTitleFromBackStack();
734 private int setTitleFromBackStack() {
735 final int count = getFragmentManager().getBackStackEntryCount();
738 if (mInitialTitleResId > 0) {
739 setTitle(mInitialTitleResId);
741 setTitle(mInitialTitle);
746 FragmentManager.BackStackEntry bse = getFragmentManager().getBackStackEntryAt(count - 1);
747 setTitleFromBackStackEntry(bse);
752 private void setTitleFromBackStackEntry(FragmentManager.BackStackEntry bse) {
753 final CharSequence title;
754 final int titleRes = bse.getBreadCrumbTitleRes();
756 title = getText(titleRes);
758 title = bse.getBreadCrumbTitle();
766 protected void onSaveInstanceState(Bundle outState) {
767 super.onSaveInstanceState(outState);
769 if (mCategories.size() > 0) {
770 outState.putParcelableArrayList(SAVE_KEY_CATEGORIES, mCategories);
773 outState.putBoolean(SAVE_KEY_SHOW_HOME_AS_UP, mDisplayHomeAsUpEnabled);
774 outState.putBoolean(SAVE_KEY_SHOW_SEARCH, mDisplaySearch);
776 if (mDisplaySearch) {
777 // The option menus are created if the ActionBar is visible and they are also created
778 // asynchronously. If you launch Settings with an Intent action like
779 // android.intent.action.POWER_USAGE_SUMMARY and at the same time your device is locked
780 // thru a LockScreen, onCreateOptionsMenu() is not yet called and references to the search
781 // menu item and search view are null.
782 boolean isExpanded = (mSearchMenuItem != null) && mSearchMenuItem.isActionViewExpanded();
783 outState.putBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED, isExpanded);
785 String query = (mSearchView != null) ? mSearchView.getQuery().toString() : EMPTY_QUERY;
786 outState.putString(SAVE_KEY_SEARCH_QUERY, query);
791 protected void onResume() {
794 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
796 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
800 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
801 mDevelopmentPreferencesListener);
803 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
804 registerReceiver(mUserAddRemoveReceiver, new IntentFilter(Intent.ACTION_USER_ADDED));
805 registerReceiver(mUserAddRemoveReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
807 mDynamicIndexableContentMonitor.register(this, LOADER_ID_INDEXABLE_CONTENT_MONITOR);
809 if(mDisplaySearch && !TextUtils.isEmpty(mSearchQuery)) {
810 onQueryTextSubmit(mSearchQuery);
816 protected void onPause() {
818 unregisterReceiver(mBatteryInfoReceiver);
819 unregisterReceiver(mUserAddRemoveReceiver);
820 mDynamicIndexableContentMonitor.unregister();
824 public void onDestroy() {
827 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
828 mDevelopmentPreferencesListener);
829 mDevelopmentPreferencesListener = null;
832 protected boolean isValidFragment(String fragmentName) {
833 // Almost all fragments are wrapped in this,
834 // except for a few that have their own activities.
835 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
836 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
842 public Intent getIntent() {
843 Intent superIntent = super.getIntent();
844 String startingFragment = getStartingFragmentClass(superIntent);
845 // This is called from super.onCreate, isMultiPane() is not yet reliable
846 // Do not use onIsHidingHeaders either, which relies itself on this method
847 if (startingFragment != null) {
848 Intent modIntent = new Intent(superIntent);
849 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
850 Bundle args = superIntent.getExtras();
852 args = new Bundle(args);
856 args.putParcelable("intent", superIntent);
857 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
864 * Checks if the component name in the intent is different from the Settings class and
865 * returns the class name to load as a fragment.
867 private String getStartingFragmentClass(Intent intent) {
868 if (mFragmentClass != null) return mFragmentClass;
870 String intentClass = intent.getComponent().getClassName();
871 if (intentClass.equals(getClass().getName())) return null;
873 if ("com.android.settings.ManageApplications".equals(intentClass)
874 || "com.android.settings.RunningServices".equals(intentClass)
875 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
876 // Old names of manage apps.
877 intentClass = com.android.settings.applications.ManageApplications.class.getName();
884 * Start a new fragment containing a preference panel. If the preferences
885 * are being displayed in multi-pane mode, the given fragment class will
886 * be instantiated and placed in the appropriate pane. If running in
887 * single-pane mode, a new activity will be launched in which to show the
890 * @param fragmentClass Full name of the class implementing the fragment.
891 * @param args Any desired arguments to supply to the fragment.
892 * @param titleRes Optional resource identifier of the title of this
894 * @param titleText Optional text of the title of this fragment.
895 * @param resultTo Optional fragment that result data should be sent to.
896 * If non-null, resultTo.onActivityResult() will be called when this
897 * preference panel is done. The launched panel must use
898 * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
899 * @param resultRequestCode If resultTo is non-null, this is the caller's
900 * request code to be received with the result.
902 public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
903 CharSequence titleText, Fragment resultTo, int resultRequestCode) {
906 if (titleText != null) {
907 title = titleText.toString();
909 // There not much we can do in that case
913 Utils.startWithFragment(this, fragmentClass, args, resultTo, resultRequestCode,
914 titleRes, title, mIsShortcut);
918 * Start a new fragment in a new activity containing a preference panel for a given user. If the
919 * preferences are being displayed in multi-pane mode, the given fragment class will be
920 * instantiated and placed in the appropriate pane. If running in single-pane mode, a new
921 * activity will be launched in which to show the fragment.
923 * @param fragmentClass Full name of the class implementing the fragment.
924 * @param args Any desired arguments to supply to the fragment.
925 * @param titleRes Optional resource identifier of the title of this fragment.
926 * @param titleText Optional text of the title of this fragment.
927 * @param userHandle The user for which the panel has to be started.
929 public void startPreferencePanelAsUser(String fragmentClass, Bundle args, int titleRes,
930 CharSequence titleText, UserHandle userHandle) {
931 // This is a workaround.
933 // Calling startWithFragmentAsUser() without specifying FLAG_ACTIVITY_NEW_TASK to the intent
934 // starting the fragment could cause a native stack corruption. See b/17523189. However,
935 // adding that flag and start the preference panel with the same UserHandler will make it
936 // impossible to use back button to return to the previous screen. See b/20042570.
938 // We work around this issue by adding FLAG_ACTIVITY_NEW_TASK to the intent, while doing
939 // another check here to call startPreferencePanel() instead of startWithFragmentAsUser()
940 // when we're calling it as the same user.
941 if (userHandle.getIdentifier() == UserHandle.myUserId()) {
942 startPreferencePanel(fragmentClass, args, titleRes, titleText, null, 0);
946 if (titleText != null) {
947 title = titleText.toString();
949 // There not much we can do in that case
953 Utils.startWithFragmentAsUser(this, fragmentClass, args,
954 titleRes, title, mIsShortcut, userHandle);
959 * Called by a preference panel fragment to finish itself.
961 * @param caller The fragment that is asking to be finished.
962 * @param resultCode Optional result code to send back to the original
963 * launching fragment.
964 * @param resultData Optional result data to send back to the original
965 * launching fragment.
967 public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
968 setResult(resultCode, resultData);
973 * Start a new fragment.
975 * @param fragment The fragment to start
976 * @param push If true, the current fragment will be pushed onto the back stack. If false,
977 * the current fragment will be replaced.
979 public void startPreferenceFragment(Fragment fragment, boolean push) {
980 FragmentTransaction transaction = getFragmentManager().beginTransaction();
981 transaction.replace(mMainContentId, fragment);
983 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
984 transaction.addToBackStack(BACK_STACK_PREFS);
986 transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
988 transaction.commitAllowingStateLoss();
992 * Switch to a specific Fragment with taking care of validation, Title and BackStack
994 private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate,
995 boolean addToBackStack, int titleResId, CharSequence title, boolean withTransition) {
996 if (validate && !isValidFragment(fragmentName)) {
997 throw new IllegalArgumentException("Invalid fragment for this activity: "
1000 Fragment f = Fragment.instantiate(this, fragmentName, args);
1001 FragmentTransaction transaction = getFragmentManager().beginTransaction();
1002 transaction.replace(mMainContentId, f);
1003 if (withTransition) {
1004 TransitionManager.beginDelayedTransition(mContent);
1006 if (addToBackStack) {
1007 transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS);
1009 if (titleResId > 0) {
1010 transaction.setBreadCrumbTitle(titleResId);
1011 } else if (title != null) {
1012 transaction.setBreadCrumbTitle(title);
1014 transaction.commitAllowingStateLoss();
1015 getFragmentManager().executePendingTransactions();
1019 private void updateTilesList() {
1020 // Generally the items that are will be changing from these updates will
1021 // not be in the top list of tiles, so run it in the background and the
1022 // SettingsDrawerActivity will pick up on the updates automatically.
1023 AsyncTask.execute(new Runnable() {
1026 doUpdateTilesList();
1031 private void doUpdateTilesList() {
1032 PackageManager pm = getPackageManager();
1033 final UserManager um = UserManager.get(this);
1034 final boolean isAdmin = um.isAdminUser();
1036 String packageName = getPackageName();
1037 setTileEnabled(new ComponentName(packageName, WifiSettingsActivity.class.getName()),
1038 pm.hasSystemFeature(PackageManager.FEATURE_WIFI), isAdmin, pm);
1040 setTileEnabled(new ComponentName(packageName,
1041 Settings.BluetoothSettingsActivity.class.getName()),
1042 pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH), isAdmin, pm);
1044 setTileEnabled(new ComponentName(packageName,
1045 Settings.DataUsageSummaryActivity.class.getName()),
1046 Utils.isBandwidthControlEnabled(), isAdmin, pm);
1048 setTileEnabled(new ComponentName(packageName,
1049 Settings.SimSettingsActivity.class.getName()),
1050 Utils.showSimCardTile(this), isAdmin, pm);
1052 setTileEnabled(new ComponentName(packageName,
1053 Settings.PowerUsageSummaryActivity.class.getName()),
1054 mBatteryPresent, isAdmin, pm);
1056 setTileEnabled(new ComponentName(packageName,
1057 Settings.UserSettingsActivity.class.getName()),
1058 UserHandle.MU_ENABLED && UserManager.supportsMultipleUsers()
1059 && !Utils.isMonkeyRunning(), isAdmin, pm);
1061 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
1062 setTileEnabled(new ComponentName(packageName,
1063 Settings.PaymentSettingsActivity.class.getName()),
1064 pm.hasSystemFeature(PackageManager.FEATURE_NFC)
1065 && pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
1066 && adapter != null && adapter.isEnabled(), isAdmin, pm);
1068 setTileEnabled(new ComponentName(packageName,
1069 Settings.PrintSettingsActivity.class.getName()),
1070 pm.hasSystemFeature(PackageManager.FEATURE_PRINTING), isAdmin, pm);
1072 final boolean showDev = mDevelopmentPreferences.getBoolean(
1073 DevelopmentSettings.PREF_SHOW, android.os.Build.TYPE.equals("eng"))
1074 && !um.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES);
1075 setTileEnabled(new ComponentName(packageName,
1076 Settings.DevelopmentSettingsActivity.class.getName()),
1077 showDev, isAdmin, pm);
1079 // Reveal development-only quick settings tiles
1080 DevelopmentTiles.setTilesEnabled(this, showDev);
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_ENABLED;
1105 if (isEnabled != enabled) {
1106 pm.setComponentEnabledSetting(component, enabled
1107 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1108 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
1109 PackageManager.DONT_KILL_APP);
1113 private void getMetaData() {
1115 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
1116 PackageManager.GET_META_DATA);
1117 if (ai == null || ai.metaData == null) return;
1118 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
1119 } catch (NameNotFoundException nnfe) {
1121 Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());
1125 // give subclasses access to the Next button
1126 public boolean hasNextButton() {
1127 return mNextButton != null;
1130 public Button getNextButton() {
1135 public boolean shouldUpRecreateTask(Intent targetIntent) {
1136 return super.shouldUpRecreateTask(new Intent(this, SettingsActivity.class));
1140 public boolean onQueryTextSubmit(String query) {
1141 switchToSearchResultsFragmentIfNeeded();
1142 mSearchQuery = query;
1143 return mSearchResultsFragment.onQueryTextSubmit(query);
1147 public boolean onQueryTextChange(String newText) {
1148 mSearchQuery = newText;
1149 if (mSearchResultsFragment == null) {
1152 return mSearchResultsFragment.onQueryTextChange(newText);
1156 public boolean onClose() {
1161 public boolean onMenuItemActionExpand(MenuItem item) {
1162 if (item.getItemId() == mSearchMenuItem.getItemId()) {
1163 switchToSearchResultsFragmentIfNeeded();
1169 public boolean onMenuItemActionCollapse(MenuItem item) {
1170 if (item.getItemId() == mSearchMenuItem.getItemId()) {
1171 if (mSearchMenuItemExpanded) {
1172 revertToInitialFragment();
1179 protected void onTileClicked(Tile tile) {
1180 if (mIsShowingDashboard) {
1181 // If on dashboard, don't finish so the back comes back to here.
1184 super.onTileClicked(tile);
1189 public void onProfileTileOpen() {
1190 if (!mIsShowingDashboard) {
1195 private void switchToSearchResultsFragmentIfNeeded() {
1196 if (mSearchResultsFragment != null) {
1199 Fragment current = getFragmentManager().findFragmentById(mMainContentId);
1200 if (current != null && current instanceof SearchResultsSummary) {
1201 mSearchResultsFragment = (SearchResultsSummary) current;
1203 mSearchResultsFragment = (SearchResultsSummary) switchToFragment(
1204 SearchResultsSummary.class.getName(), null, false, true,
1205 R.string.search_results_title, null, true);
1207 mSearchResultsFragment.setSearchView(mSearchView);
1208 mSearchMenuItemExpanded = true;
1211 public void needToRevertToInitialFragment() {
1212 mNeedToRevertToInitialFragment = true;
1215 private void revertToInitialFragment() {
1216 mNeedToRevertToInitialFragment = false;
1217 mSearchResultsFragment = null;
1218 mSearchMenuItemExpanded = false;
1219 getFragmentManager().popBackStackImmediate(SettingsActivity.BACK_STACK_PREFS,
1220 FragmentManager.POP_BACK_STACK_INCLUSIVE);
1221 if (mSearchMenuItem != null) {
1222 mSearchMenuItem.collapseActionView();
1226 public Intent getResultIntentData() {
1227 return mResultIntentData;
1230 public void setResultIntentData(Intent resultIntentData) {
1231 mResultIntentData = resultIntentData;
1234 public void startSuggestion(Intent intent) {
1235 mCurrentSuggestion = intent.getComponent();
1236 startActivityForResult(intent, REQUEST_SUGGESTION);
1240 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
1241 if (requestCode == REQUEST_SUGGESTION && mCurrentSuggestion != null
1242 && resultCode != RESULT_CANCELED) {
1243 getPackageManager().setComponentEnabledSetting(mCurrentSuggestion,
1244 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
1246 super.onActivityResult(requestCode, resultCode, data);