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