blob: 91f7fbc02731b77843ed4d7949f0e81ac49dc8a9 [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;
Gilles Debunnee78c1872011-06-20 15:00:07 -070028import android.content.Context;
Amith Yamasani379d9b02010-09-27 12:03:59 -070029import android.content.Intent;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090030import android.content.IntentFilter;
Dianne Hackborncaefa9b2012-10-10 15:05:42 -070031import android.content.SharedPreferences;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070032import android.content.pm.ActivityInfo;
33import android.content.pm.PackageManager;
34import android.content.pm.PackageManager.NameNotFoundException;
Christopher Tatee238a472013-08-27 14:21:46 -070035import android.content.pm.ResolveInfo;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070036import android.graphics.drawable.Drawable;
Martijn Coenen81ab8172013-09-30 12:07:02 -070037import android.nfc.NfcAdapter;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070038import android.os.Bundle;
Jeff Sharkey34e964d2012-04-21 15:41:48 -070039import android.os.INetworkManagementService;
40import android.os.RemoteException;
41import android.os.ServiceManager;
Dianne Hackbornbb06a422012-08-16 11:01:57 -070042import android.os.UserHandle;
Jeff Sharkey44202462012-09-19 13:13:45 -070043import android.os.UserManager;
Amith Yamasania4379d62011-07-22 10:34:58 -070044import android.preference.Preference;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070045import android.preference.PreferenceActivity;
Amith Yamasania4379d62011-07-22 10:34:58 -070046import android.preference.PreferenceFragment;
Gilles Debunnee78c1872011-06-20 15:00:07 -070047import android.text.TextUtils;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080048import android.util.Log;
Gilles Debunnee78c1872011-06-20 15:00:07 -070049import android.view.LayoutInflater;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080050import android.view.View;
51import android.view.View.OnClickListener;
Gilles Debunnee78c1872011-06-20 15:00:07 -070052import android.view.ViewGroup;
53import android.widget.ArrayAdapter;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080054import android.widget.Button;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -040055import android.widget.ImageButton;
Gilles Debunnee78c1872011-06-20 15:00:07 -070056import android.widget.ImageView;
57import android.widget.ListAdapter;
58import android.widget.Switch;
59import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080060
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080061import com.android.internal.util.ArrayUtils;
Amith Yamasania677ee22013-07-26 13:38:41 -070062import com.android.settings.accessibility.AccessibilitySettings;
Alan Viverette4098dba2013-12-04 17:19:24 -080063import com.android.settings.accessibility.CaptionPropertiesFragment;
Alan Viverette341ff662013-07-18 17:49:33 -070064import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080065import com.android.settings.accounts.AccountSyncSettings;
66import com.android.settings.accounts.AuthenticatorHelper;
67import com.android.settings.accounts.ManageAccountsSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070068import com.android.settings.applications.AppOpsSummary;
69import com.android.settings.applications.ManageApplications;
Dianne Hackbornc6d658e2013-08-08 12:57:53 -070070import com.android.settings.applications.ProcessStatsUi;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080071import com.android.settings.bluetooth.BluetoothEnabler;
72import com.android.settings.bluetooth.BluetoothSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070073import com.android.settings.deviceinfo.Memory;
74import com.android.settings.deviceinfo.UsbSettings;
75import com.android.settings.fuelgauge.PowerUsageSummary;
76import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
Amith Yamasani3a14ae22013-08-30 15:43:44 -070077import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070078import com.android.settings.inputmethod.SpellCheckersSettings;
79import com.android.settings.inputmethod.UserDictionaryList;
Amith Yamasanie9904202013-08-01 10:26:14 -070080import com.android.settings.location.LocationSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070081import com.android.settings.nfc.AndroidBeam;
Martijn Coenen53083ab2013-08-09 13:37:38 -070082import com.android.settings.nfc.PaymentSettings;
Svetoslavd9f156d2013-10-09 21:59:04 -070083import com.android.settings.print.PrintJobSettingsFragment;
Svetoslav2d531652013-09-03 21:32:40 -070084import com.android.settings.print.PrintServiceSettingsFragment;
85import com.android.settings.print.PrintSettingsFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070086import com.android.settings.tts.TextToSpeechSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070087import com.android.settings.users.UserSettings;
88import com.android.settings.vpn2.VpnSettings;
Jeff Sharkey0c3634c2013-02-20 12:35:16 -080089import com.android.settings.wfd.WifiDisplaySettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070090import com.android.settings.wifi.AdvancedWifiSettings;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080091import com.android.settings.wifi.WifiEnabler;
92import com.android.settings.wifi.WifiSettings;
93import com.android.settings.wifi.p2p.WifiP2pSettings;
94
Gilles Debunnee78c1872011-06-20 15:00:07 -070095import java.util.ArrayList;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070096import java.util.Collections;
97import java.util.Comparator;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070098import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070099import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -0700100
101/**
102 * Top-level settings activity to handle single pane and double pane UI layout.
103 */
Amith Yamasani56821db2012-06-05 13:20:45 -0700104public class Settings extends PreferenceActivity
105 implements ButtonBarHandler, OnAccountsUpdateListener {
Amith Yamasanid7993472010-08-18 13:59:28 -0700106
Gilles Debunnee78c1872011-06-20 15:00:07 -0700107 private static final String LOG_TAG = "Settings";
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700108
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700109 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700110 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700111 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700112 "com.android.settings.FRAGMENT_CLASS";
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800113 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800114 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
Christopher Tatee0d934f2013-10-01 12:32:27 -0700115
116 private static boolean sShowNoHomeNotice = false;
117
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700118 private String mFragmentClass;
119 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -0800120 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800121 private Header mCurrentHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800122 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700123
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700124 // Show only these settings for restricted users
125 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700126 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700127 R.id.wifi_settings,
128 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700129 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700130 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700131 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700132 R.id.sound_settings,
133 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700134 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700135 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700136 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700137 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700138 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700139 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700140 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700141 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700142 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700143 R.id.account_add,
144 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700145 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700146 R.id.about_settings,
Svetoslav Ganovd4c7b492013-06-11 21:15:11 -0700147 R.id.accessibility_settings,
Martijn Coenen26515da2013-08-01 18:13:33 -0700148 R.id.print_settings,
Christopher Tatee238a472013-08-27 14:21:46 -0700149 R.id.nfc_payment_settings,
150 R.id.home_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700151 };
152
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700153 private SharedPreferences mDevelopmentPreferences;
154 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
155
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700156 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700157
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700158 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
159
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700160 private AuthenticatorHelper mAuthenticatorHelper;
161 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700162 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700163
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900164 private boolean mBatteryPresent = true;
165 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
166
167 @Override
168 public void onReceive(Context context, Intent intent) {
169 String action = intent.getAction();
170 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
171 boolean batteryPresent = Utils.isBatteryPresent(intent);
172
173 if (mBatteryPresent != batteryPresent) {
174 mBatteryPresent = batteryPresent;
175 invalidateHeaders();
176 }
177 }
178 }
179 };
180
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700181 @Override
182 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800183 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
184 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700185 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700186
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700187 mAuthenticatorHelper = new AuthenticatorHelper();
188 mAuthenticatorHelper.updateAuthDescriptions(this);
189 mAuthenticatorHelper.onAccountsUpdated(this, null);
190
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700191 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
192 Context.MODE_PRIVATE);
193
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700194 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800195 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700196 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800197 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700198
Gilles Debunne3661b622011-06-27 11:19:16 -0700199 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700200 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800201 // Force the title so that it doesn't get overridden by a direct launch of
202 // a specific settings screen.
203 setTitle(R.string.settings_label);
204 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800205
206 // Retrieve any saved state
207 if (savedInstanceState != null) {
208 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800209 }
210
211 // If the current header was saved, switch to it
212 if (savedInstanceState != null && mCurrentHeader != null) {
213 //switchToHeaderLocal(mCurrentHeader);
214 showBreadCrumbs(mCurrentHeader.title, null);
215 }
216
Amith Yamasani3d384f42012-05-11 15:22:04 -0700217 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
218 if (onIsMultiPane()) {
219 getActionBar().setDisplayHomeAsUpEnabled(false);
220 getActionBar().setHomeButtonEnabled(false);
221 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800222 }
223
224 @Override
225 protected void onSaveInstanceState(Bundle outState) {
226 super.onSaveInstanceState(outState);
227
228 // Save the current fragment, if it is the same as originally launched
229 if (mCurrentHeader != null) {
230 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
231 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800232 }
233
Gilles Debunnee78c1872011-06-20 15:00:07 -0700234 @Override
235 public void onResume() {
236 super.onResume();
237
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700238 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
239 @Override
240 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
241 invalidateHeaders();
242 }
243 };
244 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
245 mDevelopmentPreferencesListener);
246
Gilles Debunnee78c1872011-06-20 15:00:07 -0700247 ListAdapter listAdapter = getListAdapter();
248 if (listAdapter instanceof HeaderAdapter) {
249 ((HeaderAdapter) listAdapter).resume();
250 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700251 invalidateHeaders();
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900252
253 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700254 }
255
256 @Override
257 public void onPause() {
258 super.onPause();
259
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900260 unregisterReceiver(mBatteryInfoReceiver);
261
Gilles Debunnee78c1872011-06-20 15:00:07 -0700262 ListAdapter listAdapter = getListAdapter();
263 if (listAdapter instanceof HeaderAdapter) {
264 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700265 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700266
267 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
268 mDevelopmentPreferencesListener);
269 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700270 }
271
272 @Override
273 public void onDestroy() {
274 super.onDestroy();
275 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700276 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700277 }
278 }
279
Amith Yamasani56f51a82013-08-05 10:07:23 -0700280 @Override
281 public boolean onIsMultiPane() {
282 return false;
283 }
284
Amith Yamasania677ee22013-07-26 13:38:41 -0700285 private static final String[] ENTRY_FRAGMENTS = {
286 WirelessSettings.class.getName(),
287 WifiSettings.class.getName(),
288 AdvancedWifiSettings.class.getName(),
289 BluetoothSettings.class.getName(),
290 TetherSettings.class.getName(),
291 WifiP2pSettings.class.getName(),
292 VpnSettings.class.getName(),
293 DateTimeSettings.class.getName(),
294 LocalePicker.class.getName(),
295 InputMethodAndLanguageSettings.class.getName(),
296 SpellCheckersSettings.class.getName(),
297 UserDictionaryList.class.getName(),
298 UserDictionarySettings.class.getName(),
299 SoundSettings.class.getName(),
300 DisplaySettings.class.getName(),
301 DeviceInfoSettings.class.getName(),
302 ManageApplications.class.getName(),
Dianne Hackbornc6d658e2013-08-08 12:57:53 -0700303 ProcessStatsUi.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700304 NotificationStation.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700305 LocationSettings.class.getName(),
306 SecuritySettings.class.getName(),
307 PrivacySettings.class.getName(),
308 DeviceAdminSettings.class.getName(),
309 AccessibilitySettings.class.getName(),
Alan Viverette4098dba2013-12-04 17:19:24 -0800310 CaptionPropertiesFragment.class.getName(),
Alan Viverettefc0ab212013-10-02 16:36:33 -0700311 com.android.settings.accessibility.ToggleInversionPreferenceFragment.class.getName(),
312 com.android.settings.accessibility.ToggleContrastPreferenceFragment.class.getName(),
313 com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700314 TextToSpeechSettings.class.getName(),
315 Memory.class.getName(),
316 DevelopmentSettings.class.getName(),
317 UsbSettings.class.getName(),
318 AndroidBeam.class.getName(),
319 WifiDisplaySettings.class.getName(),
320 PowerUsageSummary.class.getName(),
321 AccountSyncSettings.class.getName(),
322 CryptKeeperSettings.class.getName(),
323 DataUsageSummary.class.getName(),
324 DreamSettings.class.getName(),
325 UserSettings.class.getName(),
326 NotificationAccessSettings.class.getName(),
Amith Yamasaniee226f92013-08-05 11:02:16 -0700327 ManageAccountsSettings.class.getName(),
Svetoslav2d531652013-09-03 21:32:40 -0700328 PrintSettingsFragment.class.getName(),
Svetoslavd9f156d2013-10-09 21:59:04 -0700329 PrintJobSettingsFragment.class.getName(),
Martijn Coenen53083ab2013-08-09 13:37:38 -0700330 TrustedCredentialsSettings.class.getName(),
Amith Yamasani3a14ae22013-08-30 15:43:44 -0700331 PaymentSettings.class.getName(),
332 KeyboardLayoutPickerFragment.class.getName()
Amith Yamasania677ee22013-07-26 13:38:41 -0700333 };
334
335 @Override
336 protected boolean isValidFragment(String fragmentName) {
337 // Almost all fragments are wrapped in this,
338 // except for a few that have their own activities.
339 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
340 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
341 }
342 return false;
343 }
344
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800345 private void switchToHeaderLocal(Header header) {
346 mInLocalHeaderSwitch = true;
347 switchToHeader(header);
348 mInLocalHeaderSwitch = false;
349 }
350
351 @Override
352 public void switchToHeader(Header header) {
353 if (!mInLocalHeaderSwitch) {
354 mCurrentHeader = null;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800355 }
356 super.switchToHeader(header);
357 }
358
Amith Yamasani3965ae62010-11-15 14:45:19 -0800359 @Override
360 public void onNewIntent(Intent intent) {
361 super.onNewIntent(intent);
362
363 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700364 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
365 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
366 switchToHeaderLocal(mFirstHeader);
367 }
368 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800369 }
370 }
371
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700372 private void highlightHeader(int id) {
373 if (id != 0) {
374 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700375 if (index != null) {
376 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700377 if (isMultiPane()) {
378 getListView().smoothScrollToPosition(index);
379 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700380 }
381 }
382 }
383
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700384 @Override
385 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700386 Intent superIntent = super.getIntent();
387 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700388 // This is called from super.onCreate, isMultiPane() is not yet reliable
389 // Do not use onIsHidingHeaders either, which relies itself on this method
390 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700391 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700392 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700393 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700394 if (args != null) {
395 args = new Bundle(args);
396 } else {
397 args = new Bundle();
398 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700399 args.putParcelable("intent", superIntent);
400 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700401 return modIntent;
402 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700403 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700404 }
405
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700406 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700407 * Checks if the component name in the intent is different from the Settings class and
408 * returns the class name to load as a fragment.
409 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700410 protected String getStartingFragmentClass(Intent intent) {
411 if (mFragmentClass != null) return mFragmentClass;
412
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700413 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700414 if (intentClass.equals(getClass().getName())) return null;
415
Dianne Hackbornee293792010-11-01 12:32:33 -0700416 if ("com.android.settings.ManageApplications".equals(intentClass)
417 || "com.android.settings.RunningServices".equals(intentClass)
418 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700419 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700420 intentClass = com.android.settings.applications.ManageApplications.class.getName();
421 }
422
Amith Yamasani379d9b02010-09-27 12:03:59 -0700423 return intentClass;
424 }
425
426 /**
427 * Override initial header when an activity-alias is causing Settings to be launched
428 * for a specific fragment encoded in the android:name parameter.
429 */
430 @Override
431 public Header onGetInitialHeader() {
432 String fragmentClass = getStartingFragmentClass(super.getIntent());
433 if (fragmentClass != null) {
434 Header header = new Header();
435 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800436 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700437 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800438 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700439 return header;
440 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700441
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700442 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700443 }
444
Dianne Hackbornb7258182011-03-15 16:23:55 -0700445 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700446 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
447 int titleRes, int shortTitleRes) {
448 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
449 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700450
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800451 // Some fragments want split ActionBar; these should stay in sync with
452 // uiOptions for fragments also defined as activities in manifest.
453 if (WifiSettings.class.getName().equals(fragmentName) ||
454 WifiP2pSettings.class.getName().equals(fragmentName) ||
455 BluetoothSettings.class.getName().equals(fragmentName) ||
456 DreamSettings.class.getName().equals(fragmentName) ||
Lifu Tangd5fbbc42013-08-01 17:23:10 -0700457 LocationSettings.class.getName().equals(fragmentName) ||
Svetoslav2d531652013-09-03 21:32:40 -0700458 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
459 PrintSettingsFragment.class.getName().equals(fragmentName) ||
460 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800461 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700462 }
463
Dianne Hackbornb7258182011-03-15 16:23:55 -0700464 intent.setClass(this, SubSettings.class);
465 return intent;
466 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700467
Amith Yamasani379d9b02010-09-27 12:03:59 -0700468 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700469 * Populate the activity with the top-level headers.
470 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700471 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700472 public void onBuildHeaders(List<Header> headers) {
Amith Yamasani2972c012013-10-02 11:48:46 -0700473 if (!onIsHidingHeaders()) {
474 loadHeadersFromResource(R.xml.settings_headers, headers);
475 updateHeaderList(headers);
476 }
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700477 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700478
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700479 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700480 final boolean showDev = mDevelopmentPreferences.getBoolean(
481 DevelopmentSettings.PREF_SHOW,
482 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700483 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400484
485 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700486 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700487 while (i < target.size()) {
488 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700489 // Ids are integers, so downcasting
490 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400491 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700492 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700493 } else if (id == R.id.wifi_settings) {
494 // Remove WiFi Settings if WiFi service is not available.
495 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700496 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700497 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700498 } else if (id == R.id.bluetooth_settings) {
499 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700500 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700501 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700502 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700503 } else if (id == R.id.data_usage_settings) {
504 // Remove data usage when kernel module not enabled
505 final INetworkManagementService netManager = INetworkManagementService.Stub
506 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
507 try {
508 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700509 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700510 }
511 } catch (RemoteException e) {
512 // ignored
513 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900514 } else if (id == R.id.battery_settings) {
515 // Remove battery settings when battery is not available. (e.g. TV)
516
517 if (!mBatteryPresent) {
518 target.remove(i);
519 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700520 } else if (id == R.id.account_settings) {
521 int headerIndex = i + 1;
522 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700523 } else if (id == R.id.home_settings) {
Christopher Tate8243c9a2013-09-19 14:59:17 -0700524 if (!updateHomeSettingHeaders(header)) {
525 target.remove(i);
526 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700527 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700528 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700529 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700530 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700531 target.remove(i);
532 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700533 } else if (id == R.id.nfc_payment_settings) {
Martijn Coenen81ab8172013-09-30 12:07:02 -0700534 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
Martijn Coenen26515da2013-08-01 18:13:33 -0700535 target.remove(i);
Martijn Coenen81ab8172013-09-30 12:07:02 -0700536 } else {
537 // Only show if NFC is on and we have the HCE feature
538 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
539 if (!adapter.isEnabled() || !getPackageManager().hasSystemFeature(
540 PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
541 target.remove(i);
542 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700543 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700544 } else if (id == R.id.development_settings) {
545 if (!showDev) {
546 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700547 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400548 } else if (id == R.id.account_add) {
549 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
550 target.remove(i);
551 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700552 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700553
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900554 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700555 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700556 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700557 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700558 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700559
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700560 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900561 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800562 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700563 if (mFirstHeader == null &&
564 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
565 mFirstHeader = header;
566 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700567 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700568 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700569 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700570 }
571 }
572
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700573 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
574 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
575 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
576 for (String accountType : accountTypes) {
577 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700578 if (label == null) {
579 continue;
580 }
581
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700582 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
583 boolean skipToAccount = accounts.length == 1
584 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700585 Header accHeader = new Header();
586 accHeader.title = label;
587 if (accHeader.extras == null) {
588 accHeader.extras = new Bundle();
589 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700590 if (skipToAccount) {
591 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
592 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
593 accHeader.fragment = AccountSyncSettings.class.getName();
594 accHeader.fragmentArguments = new Bundle();
595 // Need this for the icon
596 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
597 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
598 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
599 accounts[0]);
600 } else {
601 accHeader.breadCrumbTitle = label;
602 accHeader.breadCrumbShortTitle = label;
603 accHeader.fragment = ManageAccountsSettings.class.getName();
604 accHeader.fragmentArguments = new Bundle();
605 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
606 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
607 accountType);
608 if (!isMultiPane()) {
609 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
610 label.toString());
611 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700612 }
613 accountHeaders.add(accHeader);
Amith Yamasani2972c012013-10-02 11:48:46 -0700614 mAuthenticatorHelper.preloadDrawableForType(this, accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700615 }
616
617 // Sort by label
618 Collections.sort(accountHeaders, new Comparator<Header>() {
619 @Override
620 public int compare(Header h1, Header h2) {
621 return h1.title.toString().compareTo(h2.title.toString());
622 }
623 });
624
625 for (Header header : accountHeaders) {
626 target.add(headerIndex++, header);
627 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700628 if (!mListeningToAccountUpdates) {
629 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
630 mListeningToAccountUpdates = true;
631 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700632 return headerIndex;
633 }
634
Christopher Tate8243c9a2013-09-19 14:59:17 -0700635 private boolean updateHomeSettingHeaders(Header header) {
Christopher Tatedc7be102013-10-08 11:30:19 -0700636 // Once we decide to show Home settings, keep showing it forever
637 SharedPreferences sp = getSharedPreferences(HomeSettings.HOME_PREFS, Context.MODE_PRIVATE);
638 if (sp.getBoolean(HomeSettings.HOME_PREFS_DO_SHOW, false)) {
639 return true;
640 }
641
Christopher Tatee238a472013-08-27 14:21:46 -0700642 try {
Jeff Sharkeyd572a032013-09-23 17:41:16 -0700643 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
644 getPackageManager().getHomeActivities(homeApps);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700645 if (homeApps.size() < 2) {
646 // When there's only one available home app, omit this settings
Christopher Tatee0d934f2013-10-01 12:32:27 -0700647 // category entirely at the top level UI. If the user just
648 // uninstalled the penultimate home app candidiate, we also
649 // now tell them about why they aren't seeing 'Home' in the list.
650 if (sShowNoHomeNotice) {
651 sShowNoHomeNotice = false;
652 NoHomeDialogFragment.show(this);
653 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700654 return false;
Christopher Tatee0d934f2013-10-01 12:32:27 -0700655 } else {
656 // Okay, we're allowing the Home settings category. Tell it, when
657 // invoked via this front door, that we'll need to be told about the
658 // case when the user uninstalls all but one home app.
659 if (header.fragmentArguments == null) {
660 header.fragmentArguments = new Bundle();
661 }
662 header.fragmentArguments.putBoolean(HomeSettings.HOME_SHOW_NOTICE, true);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700663 }
Christopher Tatee238a472013-08-27 14:21:46 -0700664 } catch (Exception e) {
665 // Can't look up the home activity; bail on configuring the icon
666 Log.w(LOG_TAG, "Problem looking up home activity!", e);
667 }
Christopher Tatedc7be102013-10-08 11:30:19 -0700668
669 sp.edit().putBoolean(HomeSettings.HOME_PREFS_DO_SHOW, true).apply();
Christopher Tate8243c9a2013-09-19 14:59:17 -0700670 return true;
Christopher Tatee238a472013-08-27 14:21:46 -0700671 }
672
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700673 private void getMetaData() {
674 try {
675 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
676 PackageManager.GET_META_DATA);
677 if (ai == null || ai.metaData == null) return;
678 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
679 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
680 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700681 // No recovery
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800682 Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700683 }
684 }
685
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800686 @Override
687 public boolean hasNextButton() {
688 return super.hasNextButton();
689 }
690
691 @Override
692 public Button getNextButton() {
693 return super.getNextButton();
694 }
695
Christopher Tatee0d934f2013-10-01 12:32:27 -0700696 public static class NoHomeDialogFragment extends DialogFragment {
697 public static void show(Activity parent) {
698 final NoHomeDialogFragment dialog = new NoHomeDialogFragment();
699 dialog.show(parent.getFragmentManager(), null);
700 }
701
702 @Override
703 public Dialog onCreateDialog(Bundle savedInstanceState) {
704 return new AlertDialog.Builder(getActivity())
705 .setMessage(R.string.only_one_home_message)
706 .setPositiveButton(android.R.string.ok, null)
707 .create();
708 }
709 }
710
Gilles Debunnee78c1872011-06-20 15:00:07 -0700711 private static class HeaderAdapter extends ArrayAdapter<Header> {
712 static final int HEADER_TYPE_CATEGORY = 0;
713 static final int HEADER_TYPE_NORMAL = 1;
714 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400715 static final int HEADER_TYPE_BUTTON = 3;
716 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700717
718 private final WifiEnabler mWifiEnabler;
719 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700720 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400721 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700722
723 private static class HeaderViewHolder {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800724 ImageView mIcon;
725 TextView mTitle;
726 TextView mSummary;
727 Switch mSwitch;
728 ImageButton mButton;
729 View mDivider;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700730 }
731
732 private LayoutInflater mInflater;
733
734 static int getHeaderType(Header header) {
735 if (header.fragment == null && header.intent == null) {
736 return HEADER_TYPE_CATEGORY;
737 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
738 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400739 } else if (header.id == R.id.security_settings) {
740 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700741 } else {
742 return HEADER_TYPE_NORMAL;
743 }
744 }
745
746 @Override
747 public int getItemViewType(int position) {
748 Header header = getItem(position);
749 return getHeaderType(header);
750 }
751
752 @Override
753 public boolean areAllItemsEnabled() {
754 return false; // because of categories
755 }
756
757 @Override
758 public boolean isEnabled(int position) {
759 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
760 }
761
762 @Override
763 public int getViewTypeCount() {
764 return HEADER_TYPE_COUNT;
765 }
766
767 @Override
768 public boolean hasStableIds() {
769 return true;
770 }
771
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700772 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400773 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700774 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700775
776 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700777 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700778
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700779 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700780 // Switches inflated from their layouts. Must be done before adapter is set in super
781 mWifiEnabler = new WifiEnabler(context, new Switch(context));
782 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400783 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700784 }
785
786 @Override
787 public View getView(int position, View convertView, ViewGroup parent) {
788 HeaderViewHolder holder;
789 Header header = getItem(position);
790 int headerType = getHeaderType(header);
791 View view = null;
792
793 if (convertView == null) {
794 holder = new HeaderViewHolder();
795 switch (headerType) {
796 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700797 view = new TextView(getContext(), null,
798 android.R.attr.listSeparatorTextViewStyle);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800799 holder.mTitle = (TextView) view;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700800 break;
801
802 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700803 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
804 false);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800805 holder.mIcon = (ImageView) view.findViewById(R.id.icon);
806 holder.mTitle = (TextView)
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700807 view.findViewById(com.android.internal.R.id.title);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800808 holder.mSummary = (TextView)
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700809 view.findViewById(com.android.internal.R.id.summary);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800810 holder.mSwitch = (Switch) view.findViewById(R.id.switchWidget);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700811 break;
812
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400813 case HEADER_TYPE_BUTTON:
814 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
815 false);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800816 holder.mIcon = (ImageView) view.findViewById(R.id.icon);
817 holder.mTitle = (TextView)
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400818 view.findViewById(com.android.internal.R.id.title);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800819 holder.mSummary = (TextView)
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400820 view.findViewById(com.android.internal.R.id.summary);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800821 holder.mButton = (ImageButton) view.findViewById(R.id.buttonWidget);
822 holder.mDivider = view.findViewById(R.id.divider);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400823 break;
824
Gilles Debunnee78c1872011-06-20 15:00:07 -0700825 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700826 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700827 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700828 false);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800829 holder.mIcon = (ImageView) view.findViewById(R.id.icon);
830 holder.mTitle = (TextView)
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700831 view.findViewById(com.android.internal.R.id.title);
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800832 holder.mSummary = (TextView)
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700833 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700834 break;
835 }
836 view.setTag(holder);
837 } else {
838 view = convertView;
839 holder = (HeaderViewHolder) view.getTag();
840 }
841
842 // All view fields must be updated every time, because the view may be recycled
843 switch (headerType) {
844 case HEADER_TYPE_CATEGORY:
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800845 holder.mTitle.setText(header.getTitle(getContext().getResources()));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700846 break;
847
848 case HEADER_TYPE_SWITCH:
849 // Would need a different treatment if the main menu had more switches
850 if (header.id == R.id.wifi_settings) {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800851 mWifiEnabler.setSwitch(holder.mSwitch);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700852 } else {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800853 mBluetoothEnabler.setSwitch(holder.mSwitch);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700854 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400855 updateCommonHeaderView(header, holder);
856 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700857
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400858 case HEADER_TYPE_BUTTON:
859 if (header.id == R.id.security_settings) {
860 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
861 if (hasCert) {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800862 holder.mButton.setVisibility(View.VISIBLE);
863 holder.mDivider.setVisibility(View.VISIBLE);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400864 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
865 if (isManaged) {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800866 holder.mButton.setImageResource(R.drawable.ic_settings_about);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400867 } else {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800868 holder.mButton.setImageResource(
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400869 android.R.drawable.stat_notify_error);
870 }
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800871 holder.mButton.setOnClickListener(new OnClickListener() {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400872 @Override
873 public void onClick(View v) {
874 Intent intent = new Intent(
875 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
876 getContext().startActivity(intent);
877 }
878 });
879 } else {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800880 holder.mButton.setVisibility(View.GONE);
881 holder.mDivider.setVisibility(View.GONE);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400882 }
883 }
884 updateCommonHeaderView(header, holder);
885 break;
886
Gilles Debunnee78c1872011-06-20 15:00:07 -0700887 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400888 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700889 break;
890 }
891
892 return view;
893 }
894
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400895 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
896 if (header.extras != null
897 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
898 String accType = header.extras.getString(
899 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
900 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
901 setHeaderIcon(holder, icon);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400902 } else {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800903 holder.mIcon.setImageResource(header.iconRes);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400904 }
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800905 holder.mTitle.setText(header.getTitle(getContext().getResources()));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400906 CharSequence summary = header.getSummary(getContext().getResources());
907 if (!TextUtils.isEmpty(summary)) {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800908 holder.mSummary.setVisibility(View.VISIBLE);
909 holder.mSummary.setText(summary);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400910 } else {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800911 holder.mSummary.setVisibility(View.GONE);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400912 }
913 }
914
Christopher Tatee238a472013-08-27 14:21:46 -0700915 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800916 ViewGroup.LayoutParams lp = holder.mIcon.getLayoutParams();
Christopher Tatee238a472013-08-27 14:21:46 -0700917 lp.width = getContext().getResources().getDimensionPixelSize(
918 R.dimen.header_icon_width);
919 lp.height = lp.width;
Fabrice Di Meglioa3d01582014-01-14 16:32:10 -0800920 holder.mIcon.setLayoutParams(lp);
921 holder.mIcon.setImageDrawable(icon);
Christopher Tatee238a472013-08-27 14:21:46 -0700922 }
923
Gilles Debunnee78c1872011-06-20 15:00:07 -0700924 public void resume() {
925 mWifiEnabler.resume();
926 mBluetoothEnabler.resume();
927 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700928
Gilles Debunnee78c1872011-06-20 15:00:07 -0700929 public void pause() {
930 mWifiEnabler.pause();
931 mBluetoothEnabler.pause();
932 }
933 }
934
935 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700936 public void onHeaderClick(Header header, int position) {
937 boolean revert = false;
938 if (header.id == R.id.account_add) {
939 revert = true;
940 }
941
942 super.onHeaderClick(header, position);
943
944 if (revert && mLastHeader != null) {
945 highlightHeader((int) mLastHeader.id);
946 } else {
947 mLastHeader = header;
948 }
949 }
950
951 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700952 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
953 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800954 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700955 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800956 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -0700957 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
958 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -0700959 if (UserManager.get(this).isLinkedUser()) {
960 titleRes = R.string.profile_info_settings_title;
961 } else {
962 titleRes = R.string.user_info_settings_title;
963 }
Amith Yamasania4379d62011-07-22 10:34:58 -0700964 }
Jean Chalard7dabe452012-05-10 18:08:07 +0900965 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
966 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -0700967 return true;
968 }
969
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400970 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -0700971 public boolean shouldUpRecreateTask(Intent targetIntent) {
972 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
973 }
974
Amith Yamasania4379d62011-07-22 10:34:58 -0700975 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700976 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700977 if (adapter == null) {
978 super.setListAdapter(null);
979 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400980 DevicePolicyManager dpm =
981 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
982 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700983 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700984 }
985
Amith Yamasani56821db2012-06-05 13:20:45 -0700986 @Override
987 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -0700988 // TODO: watch for package upgrades to invalidate cache; see 7206643
989 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -0700990 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
991 invalidateHeaders();
992 }
993
Christopher Tatee0d934f2013-10-01 12:32:27 -0700994 public static void requestHomeNotice() {
995 sShowNoHomeNotice = true;
996 }
997
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700998 /*
999 * Settings subclasses for launching independently.
1000 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001001 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1002 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1003 public static class TetherSettingsActivity extends Settings { /* empty */ }
1004 public static class VpnSettingsActivity extends Settings { /* empty */ }
1005 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1006 public static class StorageSettingsActivity extends Settings { /* empty */ }
1007 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001008 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001009 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001010 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001011 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001012 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001013 public static class LocalePickerActivity extends Settings { /* empty */ }
1014 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1015 public static class SoundSettingsActivity extends Settings { /* empty */ }
1016 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1017 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1018 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1019 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Amith Yamasania88bdd32013-11-25 11:10:00 -08001020 public static class AppOpsSummaryActivity extends Settings {
1021 @Override
1022 public boolean isValidFragment(String className) {
1023 if (AppOpsSummary.class.getName().equals(className)) {
1024 return true;
1025 }
1026 return super.isValidFragment(className);
1027 }
1028 }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001029 public static class StorageUseActivity extends Settings { /* empty */ }
1030 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1031 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001032 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Alan Viverettefc0ab212013-10-02 16:36:33 -07001033 public static class AccessibilityInversionSettingsActivity extends Settings { /* empty */ }
1034 public static class AccessibilityContrastSettingsActivity extends Settings { /* empty */ }
1035 public static class AccessibilityDaltonizerSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001036 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001037 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001038 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001039 public static class RunningServicesActivity extends Settings { /* empty */ }
1040 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1041 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1042 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1043 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1044 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1045 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1046 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001047 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001048 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001049 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001050 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001051 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001052 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001053 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001054 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001055 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001056 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001057 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001058 public static class PrintSettingsActivity extends Settings { /* empty */ }
Svetoslavd9f156d2013-10-09 21:59:04 -07001059 public static class PrintJobSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001060}