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