blob: 21999c05df10d2f9e4e37e949b613738a174672d [file] [log] [blame]
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001/*
2 * Copyright (C) 2008 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
17package com.android.settings;
18
Amith Yamasani56821db2012-06-05 13:20:45 -070019import android.accounts.Account;
20import android.accounts.AccountManager;
21import android.accounts.OnAccountsUpdateListener;
Christopher Tatee0d934f2013-10-01 12:32:27 -070022import android.app.Activity;
23import android.app.AlertDialog;
24import android.app.Dialog;
25import android.app.DialogFragment;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -040026import android.app.admin.DevicePolicyManager;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090027import android.content.BroadcastReceiver;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080028import android.content.ComponentName;
Gilles Debunnee78c1872011-06-20 15:00:07 -070029import android.content.Context;
Amith Yamasani379d9b02010-09-27 12:03:59 -070030import android.content.Intent;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090031import android.content.IntentFilter;
Dianne Hackborncaefa9b2012-10-10 15:05:42 -070032import android.content.SharedPreferences;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070033import android.content.pm.ActivityInfo;
34import android.content.pm.PackageManager;
35import android.content.pm.PackageManager.NameNotFoundException;
Christopher Tatee238a472013-08-27 14:21:46 -070036import android.content.pm.ResolveInfo;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070037import android.graphics.drawable.Drawable;
Martijn Coenen81ab8172013-09-30 12:07:02 -070038import android.nfc.NfcAdapter;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070039import android.os.Bundle;
Jeff Sharkey34e964d2012-04-21 15:41:48 -070040import android.os.INetworkManagementService;
41import android.os.RemoteException;
42import android.os.ServiceManager;
Dianne Hackbornbb06a422012-08-16 11:01:57 -070043import android.os.UserHandle;
Jeff Sharkey44202462012-09-19 13:13:45 -070044import android.os.UserManager;
Amith Yamasania4379d62011-07-22 10:34:58 -070045import android.preference.Preference;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070046import android.preference.PreferenceActivity;
Amith Yamasania4379d62011-07-22 10:34:58 -070047import android.preference.PreferenceFragment;
Gilles Debunnee78c1872011-06-20 15:00:07 -070048import android.text.TextUtils;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080049import android.util.Log;
Gilles Debunnee78c1872011-06-20 15:00:07 -070050import android.view.LayoutInflater;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080051import android.view.View;
52import android.view.View.OnClickListener;
Gilles Debunnee78c1872011-06-20 15:00:07 -070053import android.view.ViewGroup;
54import android.widget.ArrayAdapter;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080055import android.widget.Button;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -040056import android.widget.ImageButton;
Gilles Debunnee78c1872011-06-20 15:00:07 -070057import android.widget.ImageView;
58import android.widget.ListAdapter;
59import android.widget.Switch;
60import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080061
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080062import com.android.internal.util.ArrayUtils;
Amith Yamasania677ee22013-07-26 13:38:41 -070063import com.android.settings.accessibility.AccessibilitySettings;
Alan Viverette4098dba2013-12-04 17:19:24 -080064import com.android.settings.accessibility.CaptionPropertiesFragment;
Alan Viverette341ff662013-07-18 17:49:33 -070065import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080066import com.android.settings.accounts.AccountSyncSettings;
67import com.android.settings.accounts.AuthenticatorHelper;
68import com.android.settings.accounts.ManageAccountsSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070069import com.android.settings.applications.AppOpsSummary;
70import com.android.settings.applications.ManageApplications;
Dianne Hackbornc6d658e2013-08-08 12:57:53 -070071import com.android.settings.applications.ProcessStatsUi;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080072import com.android.settings.bluetooth.BluetoothEnabler;
73import com.android.settings.bluetooth.BluetoothSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070074import com.android.settings.deviceinfo.Memory;
75import com.android.settings.deviceinfo.UsbSettings;
76import com.android.settings.fuelgauge.PowerUsageSummary;
77import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
Amith Yamasani3a14ae22013-08-30 15:43:44 -070078import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070079import com.android.settings.inputmethod.SpellCheckersSettings;
80import com.android.settings.inputmethod.UserDictionaryList;
Amith Yamasanie9904202013-08-01 10:26:14 -070081import com.android.settings.location.LocationSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070082import com.android.settings.nfc.AndroidBeam;
Martijn Coenen53083ab2013-08-09 13:37:38 -070083import com.android.settings.nfc.PaymentSettings;
Svetoslavd9f156d2013-10-09 21:59:04 -070084import com.android.settings.print.PrintJobSettingsFragment;
Svetoslav2d531652013-09-03 21:32:40 -070085import com.android.settings.print.PrintServiceSettingsFragment;
86import com.android.settings.print.PrintSettingsFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070087import com.android.settings.tts.TextToSpeechSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070088import com.android.settings.users.UserSettings;
89import com.android.settings.vpn2.VpnSettings;
Jeff Sharkey0c3634c2013-02-20 12:35:16 -080090import com.android.settings.wfd.WifiDisplaySettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070091import com.android.settings.wifi.AdvancedWifiSettings;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080092import com.android.settings.wifi.WifiEnabler;
93import com.android.settings.wifi.WifiSettings;
94import com.android.settings.wifi.p2p.WifiP2pSettings;
95
Gilles Debunnee78c1872011-06-20 15:00:07 -070096import java.util.ArrayList;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070097import java.util.Collections;
98import java.util.Comparator;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070099import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700100import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -0700101
102/**
103 * Top-level settings activity to handle single pane and double pane UI layout.
104 */
Amith Yamasani56821db2012-06-05 13:20:45 -0700105public class Settings extends PreferenceActivity
106 implements ButtonBarHandler, OnAccountsUpdateListener {
Amith Yamasanid7993472010-08-18 13:59:28 -0700107
Gilles Debunnee78c1872011-06-20 15:00:07 -0700108 private static final String LOG_TAG = "Settings";
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700109
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700110 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700111 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700112 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700113 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800114 private static final String META_DATA_KEY_PARENT_TITLE =
115 "com.android.settings.PARENT_FRAGMENT_TITLE";
116 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
117 "com.android.settings.PARENT_FRAGMENT_CLASS";
118
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800119 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700120
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800121 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
122 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700123
Christopher Tatee0d934f2013-10-01 12:32:27 -0700124 static final int DIALOG_ONLY_ONE_HOME = 1;
125
126 private static boolean sShowNoHomeNotice = false;
127
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700128 private String mFragmentClass;
129 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -0800130 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800131 private Header mCurrentHeader;
132 private Header mParentHeader;
133 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700134
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700135 // Show only these settings for restricted users
136 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700137 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700138 R.id.wifi_settings,
139 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700140 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700141 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700142 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700143 R.id.sound_settings,
144 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700145 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700146 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700147 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700148 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700149 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700150 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700151 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700152 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700153 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700154 R.id.account_add,
155 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700156 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700157 R.id.about_settings,
Svetoslav Ganovd4c7b492013-06-11 21:15:11 -0700158 R.id.accessibility_settings,
Martijn Coenen26515da2013-08-01 18:13:33 -0700159 R.id.print_settings,
Christopher Tatee238a472013-08-27 14:21:46 -0700160 R.id.nfc_payment_settings,
161 R.id.home_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700162 };
163
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700164 private SharedPreferences mDevelopmentPreferences;
165 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
166
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700167 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700168
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700169 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
170
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700171 private AuthenticatorHelper mAuthenticatorHelper;
172 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700173 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700174
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900175 private boolean mBatteryPresent = true;
176 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
177
178 @Override
179 public void onReceive(Context context, Intent intent) {
180 String action = intent.getAction();
181 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
182 boolean batteryPresent = Utils.isBatteryPresent(intent);
183
184 if (mBatteryPresent != batteryPresent) {
185 mBatteryPresent = batteryPresent;
186 invalidateHeaders();
187 }
188 }
189 }
190 };
191
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700192 @Override
193 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800194 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
195 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700196 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700197
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700198 mAuthenticatorHelper = new AuthenticatorHelper();
199 mAuthenticatorHelper.updateAuthDescriptions(this);
200 mAuthenticatorHelper.onAccountsUpdated(this, null);
201
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700202 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
203 Context.MODE_PRIVATE);
204
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700205 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800206 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700207 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800208 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700209
Gilles Debunne3661b622011-06-27 11:19:16 -0700210 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700211 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800212 // Force the title so that it doesn't get overridden by a direct launch of
213 // a specific settings screen.
214 setTitle(R.string.settings_label);
215 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800216
217 // Retrieve any saved state
218 if (savedInstanceState != null) {
219 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
220 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
221 }
222
223 // If the current header was saved, switch to it
224 if (savedInstanceState != null && mCurrentHeader != null) {
225 //switchToHeaderLocal(mCurrentHeader);
226 showBreadCrumbs(mCurrentHeader.title, null);
227 }
228
229 if (mParentHeader != null) {
230 setParentTitle(mParentHeader.title, null, new OnClickListener() {
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400231 @Override
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800232 public void onClick(View v) {
233 switchToParent(mParentHeader.fragment);
234 }
235 });
236 }
Gilles Debunnedc7101f2011-06-27 12:00:49 -0700237
Amith Yamasani3d384f42012-05-11 15:22:04 -0700238 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
239 if (onIsMultiPane()) {
240 getActionBar().setDisplayHomeAsUpEnabled(false);
241 getActionBar().setHomeButtonEnabled(false);
242 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800243 }
244
245 @Override
246 protected void onSaveInstanceState(Bundle outState) {
247 super.onSaveInstanceState(outState);
248
249 // Save the current fragment, if it is the same as originally launched
250 if (mCurrentHeader != null) {
251 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
252 }
253 if (mParentHeader != null) {
254 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
255 }
256 }
257
Gilles Debunnee78c1872011-06-20 15:00:07 -0700258 @Override
259 public void onResume() {
260 super.onResume();
261
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700262 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
263 @Override
264 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
265 invalidateHeaders();
266 }
267 };
268 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
269 mDevelopmentPreferencesListener);
270
Gilles Debunnee78c1872011-06-20 15:00:07 -0700271 ListAdapter listAdapter = getListAdapter();
272 if (listAdapter instanceof HeaderAdapter) {
273 ((HeaderAdapter) listAdapter).resume();
274 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700275 invalidateHeaders();
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900276
277 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700278 }
279
280 @Override
281 public void onPause() {
282 super.onPause();
283
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900284 unregisterReceiver(mBatteryInfoReceiver);
285
Gilles Debunnee78c1872011-06-20 15:00:07 -0700286 ListAdapter listAdapter = getListAdapter();
287 if (listAdapter instanceof HeaderAdapter) {
288 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700289 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700290
291 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
292 mDevelopmentPreferencesListener);
293 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700294 }
295
296 @Override
297 public void onDestroy() {
298 super.onDestroy();
299 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700300 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700301 }
302 }
303
Amith Yamasani56f51a82013-08-05 10:07:23 -0700304 @Override
305 public boolean onIsMultiPane() {
306 return false;
307 }
308
Amith Yamasania677ee22013-07-26 13:38:41 -0700309 private static final String[] ENTRY_FRAGMENTS = {
310 WirelessSettings.class.getName(),
311 WifiSettings.class.getName(),
312 AdvancedWifiSettings.class.getName(),
313 BluetoothSettings.class.getName(),
314 TetherSettings.class.getName(),
315 WifiP2pSettings.class.getName(),
316 VpnSettings.class.getName(),
317 DateTimeSettings.class.getName(),
318 LocalePicker.class.getName(),
319 InputMethodAndLanguageSettings.class.getName(),
320 SpellCheckersSettings.class.getName(),
321 UserDictionaryList.class.getName(),
322 UserDictionarySettings.class.getName(),
323 SoundSettings.class.getName(),
324 DisplaySettings.class.getName(),
325 DeviceInfoSettings.class.getName(),
326 ManageApplications.class.getName(),
Dianne Hackbornc6d658e2013-08-08 12:57:53 -0700327 ProcessStatsUi.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700328 NotificationStation.class.getName(),
329 AppOpsSummary.class.getName(),
330 LocationSettings.class.getName(),
331 SecuritySettings.class.getName(),
332 PrivacySettings.class.getName(),
333 DeviceAdminSettings.class.getName(),
334 AccessibilitySettings.class.getName(),
Alan Viverette4098dba2013-12-04 17:19:24 -0800335 CaptionPropertiesFragment.class.getName(),
Alan Viverettefc0ab212013-10-02 16:36:33 -0700336 com.android.settings.accessibility.ToggleInversionPreferenceFragment.class.getName(),
337 com.android.settings.accessibility.ToggleContrastPreferenceFragment.class.getName(),
338 com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700339 TextToSpeechSettings.class.getName(),
340 Memory.class.getName(),
341 DevelopmentSettings.class.getName(),
342 UsbSettings.class.getName(),
343 AndroidBeam.class.getName(),
344 WifiDisplaySettings.class.getName(),
345 PowerUsageSummary.class.getName(),
346 AccountSyncSettings.class.getName(),
347 CryptKeeperSettings.class.getName(),
348 DataUsageSummary.class.getName(),
349 DreamSettings.class.getName(),
350 UserSettings.class.getName(),
351 NotificationAccessSettings.class.getName(),
Amith Yamasaniee226f92013-08-05 11:02:16 -0700352 ManageAccountsSettings.class.getName(),
Svetoslav2d531652013-09-03 21:32:40 -0700353 PrintSettingsFragment.class.getName(),
Svetoslavd9f156d2013-10-09 21:59:04 -0700354 PrintJobSettingsFragment.class.getName(),
Martijn Coenen53083ab2013-08-09 13:37:38 -0700355 TrustedCredentialsSettings.class.getName(),
Amith Yamasani3a14ae22013-08-30 15:43:44 -0700356 PaymentSettings.class.getName(),
357 KeyboardLayoutPickerFragment.class.getName()
Amith Yamasania677ee22013-07-26 13:38:41 -0700358 };
359
360 @Override
361 protected boolean isValidFragment(String fragmentName) {
362 // Almost all fragments are wrapped in this,
363 // except for a few that have their own activities.
364 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
365 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
366 }
367 return false;
368 }
369
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800370 private void switchToHeaderLocal(Header header) {
371 mInLocalHeaderSwitch = true;
372 switchToHeader(header);
373 mInLocalHeaderSwitch = false;
374 }
375
376 @Override
377 public void switchToHeader(Header header) {
378 if (!mInLocalHeaderSwitch) {
379 mCurrentHeader = null;
380 mParentHeader = null;
381 }
382 super.switchToHeader(header);
383 }
384
385 /**
386 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800387 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800388 */
389 private void switchToParent(String className) {
390 final ComponentName cn = new ComponentName(this, className);
391 try {
392 final PackageManager pm = getPackageManager();
393 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
394
395 if (parentInfo != null && parentInfo.metaData != null) {
396 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
397 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
398 Header parentHeader = new Header();
399 parentHeader.fragment = fragmentClass;
400 parentHeader.title = fragmentTitle;
401 mCurrentHeader = parentHeader;
402
403 switchToHeaderLocal(parentHeader);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700404 highlightHeader(mTopLevelHeaderId);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800405
406 mParentHeader = new Header();
407 mParentHeader.fragment
408 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
409 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
410 }
411 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700412 Log.w(LOG_TAG, "Could not find parent activity : " + className);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800413 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700414 }
415
Amith Yamasani3965ae62010-11-15 14:45:19 -0800416 @Override
417 public void onNewIntent(Intent intent) {
418 super.onNewIntent(intent);
419
420 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700421 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
422 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
423 switchToHeaderLocal(mFirstHeader);
424 }
425 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800426 }
427 }
428
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700429 private void highlightHeader(int id) {
430 if (id != 0) {
431 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700432 if (index != null) {
433 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700434 if (isMultiPane()) {
435 getListView().smoothScrollToPosition(index);
436 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700437 }
438 }
439 }
440
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700441 @Override
442 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700443 Intent superIntent = super.getIntent();
444 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700445 // This is called from super.onCreate, isMultiPane() is not yet reliable
446 // Do not use onIsHidingHeaders either, which relies itself on this method
447 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700448 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700449 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700450 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700451 if (args != null) {
452 args = new Bundle(args);
453 } else {
454 args = new Bundle();
455 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700456 args.putParcelable("intent", superIntent);
457 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700458 return modIntent;
459 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700460 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700461 }
462
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700463 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700464 * Checks if the component name in the intent is different from the Settings class and
465 * returns the class name to load as a fragment.
466 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700467 protected String getStartingFragmentClass(Intent intent) {
468 if (mFragmentClass != null) return mFragmentClass;
469
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700470 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700471 if (intentClass.equals(getClass().getName())) return null;
472
Dianne Hackbornee293792010-11-01 12:32:33 -0700473 if ("com.android.settings.ManageApplications".equals(intentClass)
474 || "com.android.settings.RunningServices".equals(intentClass)
475 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700476 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700477 intentClass = com.android.settings.applications.ManageApplications.class.getName();
478 }
479
Amith Yamasani379d9b02010-09-27 12:03:59 -0700480 return intentClass;
481 }
482
483 /**
484 * Override initial header when an activity-alias is causing Settings to be launched
485 * for a specific fragment encoded in the android:name parameter.
486 */
487 @Override
488 public Header onGetInitialHeader() {
489 String fragmentClass = getStartingFragmentClass(super.getIntent());
490 if (fragmentClass != null) {
491 Header header = new Header();
492 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800493 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700494 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800495 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700496 return header;
497 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700498
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700499 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700500 }
501
Dianne Hackbornb7258182011-03-15 16:23:55 -0700502 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700503 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
504 int titleRes, int shortTitleRes) {
505 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
506 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700507
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800508 // Some fragments want split ActionBar; these should stay in sync with
509 // uiOptions for fragments also defined as activities in manifest.
510 if (WifiSettings.class.getName().equals(fragmentName) ||
511 WifiP2pSettings.class.getName().equals(fragmentName) ||
512 BluetoothSettings.class.getName().equals(fragmentName) ||
513 DreamSettings.class.getName().equals(fragmentName) ||
Lifu Tangd5fbbc42013-08-01 17:23:10 -0700514 LocationSettings.class.getName().equals(fragmentName) ||
Svetoslav2d531652013-09-03 21:32:40 -0700515 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
516 PrintSettingsFragment.class.getName().equals(fragmentName) ||
517 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800518 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700519 }
520
Dianne Hackbornb7258182011-03-15 16:23:55 -0700521 intent.setClass(this, SubSettings.class);
522 return intent;
523 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700524
Amith Yamasani379d9b02010-09-27 12:03:59 -0700525 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700526 * Populate the activity with the top-level headers.
527 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700528 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700529 public void onBuildHeaders(List<Header> headers) {
Amith Yamasani2972c012013-10-02 11:48:46 -0700530 if (!onIsHidingHeaders()) {
531 loadHeadersFromResource(R.xml.settings_headers, headers);
532 updateHeaderList(headers);
533 }
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700534 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700535
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700536 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700537 final boolean showDev = mDevelopmentPreferences.getBoolean(
538 DevelopmentSettings.PREF_SHOW,
539 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700540 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400541
542 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700543 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700544 while (i < target.size()) {
545 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700546 // Ids are integers, so downcasting
547 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400548 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700549 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700550 } else if (id == R.id.wifi_settings) {
551 // Remove WiFi Settings if WiFi service is not available.
552 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700553 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700554 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700555 } else if (id == R.id.bluetooth_settings) {
556 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700557 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700558 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700559 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700560 } else if (id == R.id.data_usage_settings) {
561 // Remove data usage when kernel module not enabled
562 final INetworkManagementService netManager = INetworkManagementService.Stub
563 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
564 try {
565 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700566 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700567 }
568 } catch (RemoteException e) {
569 // ignored
570 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900571 } else if (id == R.id.battery_settings) {
572 // Remove battery settings when battery is not available. (e.g. TV)
573
574 if (!mBatteryPresent) {
575 target.remove(i);
576 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700577 } else if (id == R.id.account_settings) {
578 int headerIndex = i + 1;
579 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700580 } else if (id == R.id.home_settings) {
Christopher Tate8243c9a2013-09-19 14:59:17 -0700581 if (!updateHomeSettingHeaders(header)) {
582 target.remove(i);
583 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700584 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700585 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700586 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700587 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700588 target.remove(i);
589 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700590 } else if (id == R.id.nfc_payment_settings) {
Martijn Coenen81ab8172013-09-30 12:07:02 -0700591 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
Martijn Coenen26515da2013-08-01 18:13:33 -0700592 target.remove(i);
Martijn Coenen81ab8172013-09-30 12:07:02 -0700593 } else {
594 // Only show if NFC is on and we have the HCE feature
595 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
596 if (!adapter.isEnabled() || !getPackageManager().hasSystemFeature(
597 PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
598 target.remove(i);
599 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700600 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700601 } else if (id == R.id.development_settings) {
602 if (!showDev) {
603 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700604 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400605 } else if (id == R.id.account_add) {
606 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
607 target.remove(i);
608 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700609 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700610
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900611 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700612 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700613 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700614 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700615 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700616
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700617 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900618 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800619 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700620 if (mFirstHeader == null &&
621 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
622 mFirstHeader = header;
623 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700624 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700625 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700626 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700627 }
628 }
629
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700630 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
631 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
632 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
633 for (String accountType : accountTypes) {
634 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700635 if (label == null) {
636 continue;
637 }
638
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700639 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
640 boolean skipToAccount = accounts.length == 1
641 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700642 Header accHeader = new Header();
643 accHeader.title = label;
644 if (accHeader.extras == null) {
645 accHeader.extras = new Bundle();
646 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700647 if (skipToAccount) {
648 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
649 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
650 accHeader.fragment = AccountSyncSettings.class.getName();
651 accHeader.fragmentArguments = new Bundle();
652 // Need this for the icon
653 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
654 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
655 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
656 accounts[0]);
657 } else {
658 accHeader.breadCrumbTitle = label;
659 accHeader.breadCrumbShortTitle = label;
660 accHeader.fragment = ManageAccountsSettings.class.getName();
661 accHeader.fragmentArguments = new Bundle();
662 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
663 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
664 accountType);
665 if (!isMultiPane()) {
666 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
667 label.toString());
668 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700669 }
670 accountHeaders.add(accHeader);
Amith Yamasani2972c012013-10-02 11:48:46 -0700671 mAuthenticatorHelper.preloadDrawableForType(this, accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700672 }
673
674 // Sort by label
675 Collections.sort(accountHeaders, new Comparator<Header>() {
676 @Override
677 public int compare(Header h1, Header h2) {
678 return h1.title.toString().compareTo(h2.title.toString());
679 }
680 });
681
682 for (Header header : accountHeaders) {
683 target.add(headerIndex++, header);
684 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700685 if (!mListeningToAccountUpdates) {
686 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
687 mListeningToAccountUpdates = true;
688 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700689 return headerIndex;
690 }
691
Christopher Tate8243c9a2013-09-19 14:59:17 -0700692 private boolean updateHomeSettingHeaders(Header header) {
Christopher Tatedc7be102013-10-08 11:30:19 -0700693 // Once we decide to show Home settings, keep showing it forever
694 SharedPreferences sp = getSharedPreferences(HomeSettings.HOME_PREFS, Context.MODE_PRIVATE);
695 if (sp.getBoolean(HomeSettings.HOME_PREFS_DO_SHOW, false)) {
696 return true;
697 }
698
Christopher Tatee238a472013-08-27 14:21:46 -0700699 try {
Jeff Sharkeyd572a032013-09-23 17:41:16 -0700700 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
701 getPackageManager().getHomeActivities(homeApps);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700702 if (homeApps.size() < 2) {
703 // When there's only one available home app, omit this settings
Christopher Tatee0d934f2013-10-01 12:32:27 -0700704 // category entirely at the top level UI. If the user just
705 // uninstalled the penultimate home app candidiate, we also
706 // now tell them about why they aren't seeing 'Home' in the list.
707 if (sShowNoHomeNotice) {
708 sShowNoHomeNotice = false;
709 NoHomeDialogFragment.show(this);
710 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700711 return false;
Christopher Tatee0d934f2013-10-01 12:32:27 -0700712 } else {
713 // Okay, we're allowing the Home settings category. Tell it, when
714 // invoked via this front door, that we'll need to be told about the
715 // case when the user uninstalls all but one home app.
716 if (header.fragmentArguments == null) {
717 header.fragmentArguments = new Bundle();
718 }
719 header.fragmentArguments.putBoolean(HomeSettings.HOME_SHOW_NOTICE, true);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700720 }
Christopher Tatee238a472013-08-27 14:21:46 -0700721 } catch (Exception e) {
722 // Can't look up the home activity; bail on configuring the icon
723 Log.w(LOG_TAG, "Problem looking up home activity!", e);
724 }
Christopher Tatedc7be102013-10-08 11:30:19 -0700725
726 sp.edit().putBoolean(HomeSettings.HOME_PREFS_DO_SHOW, true).apply();
Christopher Tate8243c9a2013-09-19 14:59:17 -0700727 return true;
Christopher Tatee238a472013-08-27 14:21:46 -0700728 }
729
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700730 private void getMetaData() {
731 try {
732 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
733 PackageManager.GET_META_DATA);
734 if (ai == null || ai.metaData == null) return;
735 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
736 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700737
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800738 // Check if it has a parent specified and create a Header object
739 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
740 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
741 if (parentFragmentClass != null) {
742 mParentHeader = new Header();
743 mParentHeader.fragment = parentFragmentClass;
744 if (parentHeaderTitleRes != 0) {
745 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
746 }
747 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700748 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700749 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700750 }
751 }
752
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800753 @Override
754 public boolean hasNextButton() {
755 return super.hasNextButton();
756 }
757
758 @Override
759 public Button getNextButton() {
760 return super.getNextButton();
761 }
762
Christopher Tatee0d934f2013-10-01 12:32:27 -0700763 public static class NoHomeDialogFragment extends DialogFragment {
764 public static void show(Activity parent) {
765 final NoHomeDialogFragment dialog = new NoHomeDialogFragment();
766 dialog.show(parent.getFragmentManager(), null);
767 }
768
769 @Override
770 public Dialog onCreateDialog(Bundle savedInstanceState) {
771 return new AlertDialog.Builder(getActivity())
772 .setMessage(R.string.only_one_home_message)
773 .setPositiveButton(android.R.string.ok, null)
774 .create();
775 }
776 }
777
Gilles Debunnee78c1872011-06-20 15:00:07 -0700778 private static class HeaderAdapter extends ArrayAdapter<Header> {
779 static final int HEADER_TYPE_CATEGORY = 0;
780 static final int HEADER_TYPE_NORMAL = 1;
781 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400782 static final int HEADER_TYPE_BUTTON = 3;
783 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700784
785 private final WifiEnabler mWifiEnabler;
786 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700787 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400788 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700789
790 private static class HeaderViewHolder {
791 ImageView icon;
792 TextView title;
793 TextView summary;
794 Switch switch_;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400795 ImageButton button_;
796 View divider_;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700797 }
798
799 private LayoutInflater mInflater;
800
801 static int getHeaderType(Header header) {
802 if (header.fragment == null && header.intent == null) {
803 return HEADER_TYPE_CATEGORY;
804 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
805 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400806 } else if (header.id == R.id.security_settings) {
807 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700808 } else {
809 return HEADER_TYPE_NORMAL;
810 }
811 }
812
813 @Override
814 public int getItemViewType(int position) {
815 Header header = getItem(position);
816 return getHeaderType(header);
817 }
818
819 @Override
820 public boolean areAllItemsEnabled() {
821 return false; // because of categories
822 }
823
824 @Override
825 public boolean isEnabled(int position) {
826 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
827 }
828
829 @Override
830 public int getViewTypeCount() {
831 return HEADER_TYPE_COUNT;
832 }
833
834 @Override
835 public boolean hasStableIds() {
836 return true;
837 }
838
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700839 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400840 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700841 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700842
843 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700844 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700845
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700846 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700847 // Switches inflated from their layouts. Must be done before adapter is set in super
848 mWifiEnabler = new WifiEnabler(context, new Switch(context));
849 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400850 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700851 }
852
853 @Override
854 public View getView(int position, View convertView, ViewGroup parent) {
855 HeaderViewHolder holder;
856 Header header = getItem(position);
857 int headerType = getHeaderType(header);
858 View view = null;
859
860 if (convertView == null) {
861 holder = new HeaderViewHolder();
862 switch (headerType) {
863 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700864 view = new TextView(getContext(), null,
865 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700866 holder.title = (TextView) view;
867 break;
868
869 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700870 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
871 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700872 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700873 holder.title = (TextView)
874 view.findViewById(com.android.internal.R.id.title);
875 holder.summary = (TextView)
876 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700877 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
878 break;
879
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400880 case HEADER_TYPE_BUTTON:
881 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
882 false);
883 holder.icon = (ImageView) view.findViewById(R.id.icon);
884 holder.title = (TextView)
885 view.findViewById(com.android.internal.R.id.title);
886 holder.summary = (TextView)
887 view.findViewById(com.android.internal.R.id.summary);
888 holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget);
889 holder.divider_ = view.findViewById(R.id.divider);
890 break;
891
Gilles Debunnee78c1872011-06-20 15:00:07 -0700892 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700893 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700894 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700895 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700896 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700897 holder.title = (TextView)
898 view.findViewById(com.android.internal.R.id.title);
899 holder.summary = (TextView)
900 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700901 break;
902 }
903 view.setTag(holder);
904 } else {
905 view = convertView;
906 holder = (HeaderViewHolder) view.getTag();
907 }
908
909 // All view fields must be updated every time, because the view may be recycled
910 switch (headerType) {
911 case HEADER_TYPE_CATEGORY:
912 holder.title.setText(header.getTitle(getContext().getResources()));
913 break;
914
915 case HEADER_TYPE_SWITCH:
916 // Would need a different treatment if the main menu had more switches
917 if (header.id == R.id.wifi_settings) {
918 mWifiEnabler.setSwitch(holder.switch_);
919 } else {
920 mBluetoothEnabler.setSwitch(holder.switch_);
921 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400922 updateCommonHeaderView(header, holder);
923 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700924
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400925 case HEADER_TYPE_BUTTON:
926 if (header.id == R.id.security_settings) {
927 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
928 if (hasCert) {
929 holder.button_.setVisibility(View.VISIBLE);
930 holder.divider_.setVisibility(View.VISIBLE);
931 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
932 if (isManaged) {
Maggie Benthall273155c2013-09-18 16:53:23 -0400933 holder.button_.setImageResource(R.drawable.ic_settings_about);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400934 } else {
935 holder.button_.setImageResource(
936 android.R.drawable.stat_notify_error);
937 }
938 holder.button_.setOnClickListener(new OnClickListener() {
939 @Override
940 public void onClick(View v) {
941 Intent intent = new Intent(
942 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
943 getContext().startActivity(intent);
944 }
945 });
946 } else {
947 holder.button_.setVisibility(View.GONE);
948 holder.divider_.setVisibility(View.GONE);
949 }
950 }
951 updateCommonHeaderView(header, holder);
952 break;
953
Gilles Debunnee78c1872011-06-20 15:00:07 -0700954 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400955 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700956 break;
957 }
958
959 return view;
960 }
961
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400962 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
963 if (header.extras != null
964 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
965 String accType = header.extras.getString(
966 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
967 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
968 setHeaderIcon(holder, icon);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400969 } else {
970 holder.icon.setImageResource(header.iconRes);
971 }
972 holder.title.setText(header.getTitle(getContext().getResources()));
973 CharSequence summary = header.getSummary(getContext().getResources());
974 if (!TextUtils.isEmpty(summary)) {
975 holder.summary.setVisibility(View.VISIBLE);
976 holder.summary.setText(summary);
977 } else {
978 holder.summary.setVisibility(View.GONE);
979 }
980 }
981
Christopher Tatee238a472013-08-27 14:21:46 -0700982 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
983 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
984 lp.width = getContext().getResources().getDimensionPixelSize(
985 R.dimen.header_icon_width);
986 lp.height = lp.width;
987 holder.icon.setLayoutParams(lp);
988 holder.icon.setImageDrawable(icon);
989 }
990
Gilles Debunnee78c1872011-06-20 15:00:07 -0700991 public void resume() {
992 mWifiEnabler.resume();
993 mBluetoothEnabler.resume();
994 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700995
Gilles Debunnee78c1872011-06-20 15:00:07 -0700996 public void pause() {
997 mWifiEnabler.pause();
998 mBluetoothEnabler.pause();
999 }
1000 }
1001
1002 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -07001003 public void onHeaderClick(Header header, int position) {
1004 boolean revert = false;
1005 if (header.id == R.id.account_add) {
1006 revert = true;
1007 }
1008
1009 super.onHeaderClick(header, position);
1010
1011 if (revert && mLastHeader != null) {
1012 highlightHeader((int) mLastHeader.id);
1013 } else {
1014 mLastHeader = header;
1015 }
1016 }
1017
1018 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -07001019 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
1020 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -08001021 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -07001022 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -08001023 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -07001024 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
1025 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -07001026 if (UserManager.get(this).isLinkedUser()) {
1027 titleRes = R.string.profile_info_settings_title;
1028 } else {
1029 titleRes = R.string.user_info_settings_title;
1030 }
Amith Yamasania4379d62011-07-22 10:34:58 -07001031 }
Jean Chalard7dabe452012-05-10 18:08:07 +09001032 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
1033 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -07001034 return true;
1035 }
1036
Maggie Benthall0c5a4012013-03-14 17:41:27 -04001037 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -07001038 public boolean shouldUpRecreateTask(Intent targetIntent) {
1039 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
1040 }
1041
Amith Yamasania4379d62011-07-22 10:34:58 -07001042 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -07001043 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -07001044 if (adapter == null) {
1045 super.setListAdapter(null);
1046 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -04001047 DevicePolicyManager dpm =
1048 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
1049 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -07001050 }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001051 }
1052
Amith Yamasani56821db2012-06-05 13:20:45 -07001053 @Override
1054 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -07001055 // TODO: watch for package upgrades to invalidate cache; see 7206643
1056 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -07001057 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
1058 invalidateHeaders();
1059 }
1060
Christopher Tatee0d934f2013-10-01 12:32:27 -07001061 public static void requestHomeNotice() {
1062 sShowNoHomeNotice = true;
1063 }
1064
Amith Yamasani5203bdf2010-11-04 09:59:44 -07001065 /*
1066 * Settings subclasses for launching independently.
1067 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001068 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1069 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1070 public static class TetherSettingsActivity extends Settings { /* empty */ }
1071 public static class VpnSettingsActivity extends Settings { /* empty */ }
1072 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1073 public static class StorageSettingsActivity extends Settings { /* empty */ }
1074 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001075 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001076 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001077 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001078 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001079 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001080 public static class LocalePickerActivity extends Settings { /* empty */ }
1081 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1082 public static class SoundSettingsActivity extends Settings { /* empty */ }
1083 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1084 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1085 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1086 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Dianne Hackborna522a8e2013-01-15 19:02:05 -08001087 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001088 public static class StorageUseActivity extends Settings { /* empty */ }
1089 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1090 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001091 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Alan Viverettefc0ab212013-10-02 16:36:33 -07001092 public static class AccessibilityInversionSettingsActivity extends Settings { /* empty */ }
1093 public static class AccessibilityContrastSettingsActivity extends Settings { /* empty */ }
1094 public static class AccessibilityDaltonizerSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001095 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001096 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001097 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001098 public static class RunningServicesActivity extends Settings { /* empty */ }
1099 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1100 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1101 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1102 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1103 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1104 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1105 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001106 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001107 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001108 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001109 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001110 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001111 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001112 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001113 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001114 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001115 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001116 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001117 public static class PrintSettingsActivity extends Settings { /* empty */ }
Svetoslavd9f156d2013-10-09 21:59:04 -07001118 public static class PrintJobSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001119}