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