blob: 2e31318e301fa056cff9ce95526ca6b9e0bbfcbb [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";
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800114 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800115 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
Christopher Tatee0d934f2013-10-01 12:32:27 -0700116
117 private static boolean sShowNoHomeNotice = false;
118
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700119 private String mFragmentClass;
120 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -0800121 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800122 private Header mCurrentHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800123 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700124
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700125 // Show only these settings for restricted users
126 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700127 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700128 R.id.wifi_settings,
129 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700130 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700131 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700132 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700133 R.id.sound_settings,
134 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700135 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700136 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700137 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700138 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700139 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700140 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700141 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700142 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700143 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700144 R.id.account_add,
145 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700146 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700147 R.id.about_settings,
Svetoslav Ganovd4c7b492013-06-11 21:15:11 -0700148 R.id.accessibility_settings,
Martijn Coenen26515da2013-08-01 18:13:33 -0700149 R.id.print_settings,
Christopher Tatee238a472013-08-27 14:21:46 -0700150 R.id.nfc_payment_settings,
151 R.id.home_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700152 };
153
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700154 private SharedPreferences mDevelopmentPreferences;
155 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
156
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700157 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700158
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700159 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
160
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700161 private AuthenticatorHelper mAuthenticatorHelper;
162 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700163 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700164
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900165 private boolean mBatteryPresent = true;
166 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
167
168 @Override
169 public void onReceive(Context context, Intent intent) {
170 String action = intent.getAction();
171 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
172 boolean batteryPresent = Utils.isBatteryPresent(intent);
173
174 if (mBatteryPresent != batteryPresent) {
175 mBatteryPresent = batteryPresent;
176 invalidateHeaders();
177 }
178 }
179 }
180 };
181
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700182 @Override
183 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800184 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
185 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700186 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700187
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700188 mAuthenticatorHelper = new AuthenticatorHelper();
189 mAuthenticatorHelper.updateAuthDescriptions(this);
190 mAuthenticatorHelper.onAccountsUpdated(this, null);
191
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700192 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
193 Context.MODE_PRIVATE);
194
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700195 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800196 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700197 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800198 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700199
Gilles Debunne3661b622011-06-27 11:19:16 -0700200 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700201 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800202 // Force the title so that it doesn't get overridden by a direct launch of
203 // a specific settings screen.
204 setTitle(R.string.settings_label);
205 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800206
207 // Retrieve any saved state
208 if (savedInstanceState != null) {
209 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800210 }
211
212 // If the current header was saved, switch to it
213 if (savedInstanceState != null && mCurrentHeader != null) {
214 //switchToHeaderLocal(mCurrentHeader);
215 showBreadCrumbs(mCurrentHeader.title, null);
216 }
217
Amith Yamasani3d384f42012-05-11 15:22:04 -0700218 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
219 if (onIsMultiPane()) {
220 getActionBar().setDisplayHomeAsUpEnabled(false);
221 getActionBar().setHomeButtonEnabled(false);
222 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800223 }
224
225 @Override
226 protected void onSaveInstanceState(Bundle outState) {
227 super.onSaveInstanceState(outState);
228
229 // Save the current fragment, if it is the same as originally launched
230 if (mCurrentHeader != null) {
231 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
232 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800233 }
234
Gilles Debunnee78c1872011-06-20 15:00:07 -0700235 @Override
236 public void onResume() {
237 super.onResume();
238
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700239 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
240 @Override
241 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
242 invalidateHeaders();
243 }
244 };
245 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
246 mDevelopmentPreferencesListener);
247
Gilles Debunnee78c1872011-06-20 15:00:07 -0700248 ListAdapter listAdapter = getListAdapter();
249 if (listAdapter instanceof HeaderAdapter) {
250 ((HeaderAdapter) listAdapter).resume();
251 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700252 invalidateHeaders();
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900253
254 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700255 }
256
257 @Override
258 public void onPause() {
259 super.onPause();
260
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900261 unregisterReceiver(mBatteryInfoReceiver);
262
Gilles Debunnee78c1872011-06-20 15:00:07 -0700263 ListAdapter listAdapter = getListAdapter();
264 if (listAdapter instanceof HeaderAdapter) {
265 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700266 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700267
268 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
269 mDevelopmentPreferencesListener);
270 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700271 }
272
273 @Override
274 public void onDestroy() {
275 super.onDestroy();
276 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700277 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700278 }
279 }
280
Amith Yamasani56f51a82013-08-05 10:07:23 -0700281 @Override
282 public boolean onIsMultiPane() {
283 return false;
284 }
285
Amith Yamasania677ee22013-07-26 13:38:41 -0700286 private static final String[] ENTRY_FRAGMENTS = {
287 WirelessSettings.class.getName(),
288 WifiSettings.class.getName(),
289 AdvancedWifiSettings.class.getName(),
290 BluetoothSettings.class.getName(),
291 TetherSettings.class.getName(),
292 WifiP2pSettings.class.getName(),
293 VpnSettings.class.getName(),
294 DateTimeSettings.class.getName(),
295 LocalePicker.class.getName(),
296 InputMethodAndLanguageSettings.class.getName(),
297 SpellCheckersSettings.class.getName(),
298 UserDictionaryList.class.getName(),
299 UserDictionarySettings.class.getName(),
300 SoundSettings.class.getName(),
301 DisplaySettings.class.getName(),
302 DeviceInfoSettings.class.getName(),
303 ManageApplications.class.getName(),
Dianne Hackbornc6d658e2013-08-08 12:57:53 -0700304 ProcessStatsUi.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700305 NotificationStation.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700306 LocationSettings.class.getName(),
307 SecuritySettings.class.getName(),
308 PrivacySettings.class.getName(),
309 DeviceAdminSettings.class.getName(),
310 AccessibilitySettings.class.getName(),
Alan Viverette4098dba2013-12-04 17:19:24 -0800311 CaptionPropertiesFragment.class.getName(),
Alan Viverettefc0ab212013-10-02 16:36:33 -0700312 com.android.settings.accessibility.ToggleInversionPreferenceFragment.class.getName(),
313 com.android.settings.accessibility.ToggleContrastPreferenceFragment.class.getName(),
314 com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700315 TextToSpeechSettings.class.getName(),
316 Memory.class.getName(),
317 DevelopmentSettings.class.getName(),
318 UsbSettings.class.getName(),
319 AndroidBeam.class.getName(),
320 WifiDisplaySettings.class.getName(),
321 PowerUsageSummary.class.getName(),
322 AccountSyncSettings.class.getName(),
323 CryptKeeperSettings.class.getName(),
324 DataUsageSummary.class.getName(),
325 DreamSettings.class.getName(),
326 UserSettings.class.getName(),
327 NotificationAccessSettings.class.getName(),
Amith Yamasaniee226f92013-08-05 11:02:16 -0700328 ManageAccountsSettings.class.getName(),
Svetoslav2d531652013-09-03 21:32:40 -0700329 PrintSettingsFragment.class.getName(),
Svetoslavd9f156d2013-10-09 21:59:04 -0700330 PrintJobSettingsFragment.class.getName(),
Martijn Coenen53083ab2013-08-09 13:37:38 -0700331 TrustedCredentialsSettings.class.getName(),
Amith Yamasani3a14ae22013-08-30 15:43:44 -0700332 PaymentSettings.class.getName(),
333 KeyboardLayoutPickerFragment.class.getName()
Amith Yamasania677ee22013-07-26 13:38:41 -0700334 };
335
336 @Override
337 protected boolean isValidFragment(String fragmentName) {
338 // Almost all fragments are wrapped in this,
339 // except for a few that have their own activities.
340 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
341 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
342 }
343 return false;
344 }
345
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800346 private void switchToHeaderLocal(Header header) {
347 mInLocalHeaderSwitch = true;
348 switchToHeader(header);
349 mInLocalHeaderSwitch = false;
350 }
351
352 @Override
353 public void switchToHeader(Header header) {
354 if (!mInLocalHeaderSwitch) {
355 mCurrentHeader = null;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800356 }
357 super.switchToHeader(header);
358 }
359
Amith Yamasani3965ae62010-11-15 14:45:19 -0800360 @Override
361 public void onNewIntent(Intent intent) {
362 super.onNewIntent(intent);
363
364 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700365 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
366 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
367 switchToHeaderLocal(mFirstHeader);
368 }
369 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800370 }
371 }
372
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700373 private void highlightHeader(int id) {
374 if (id != 0) {
375 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700376 if (index != null) {
377 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700378 if (isMultiPane()) {
379 getListView().smoothScrollToPosition(index);
380 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700381 }
382 }
383 }
384
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700385 @Override
386 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700387 Intent superIntent = super.getIntent();
388 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700389 // This is called from super.onCreate, isMultiPane() is not yet reliable
390 // Do not use onIsHidingHeaders either, which relies itself on this method
391 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700392 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700393 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700394 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700395 if (args != null) {
396 args = new Bundle(args);
397 } else {
398 args = new Bundle();
399 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700400 args.putParcelable("intent", superIntent);
401 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700402 return modIntent;
403 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700404 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700405 }
406
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700407 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700408 * Checks if the component name in the intent is different from the Settings class and
409 * returns the class name to load as a fragment.
410 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700411 protected String getStartingFragmentClass(Intent intent) {
412 if (mFragmentClass != null) return mFragmentClass;
413
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700414 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700415 if (intentClass.equals(getClass().getName())) return null;
416
Dianne Hackbornee293792010-11-01 12:32:33 -0700417 if ("com.android.settings.ManageApplications".equals(intentClass)
418 || "com.android.settings.RunningServices".equals(intentClass)
419 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700420 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700421 intentClass = com.android.settings.applications.ManageApplications.class.getName();
422 }
423
Amith Yamasani379d9b02010-09-27 12:03:59 -0700424 return intentClass;
425 }
426
427 /**
428 * Override initial header when an activity-alias is causing Settings to be launched
429 * for a specific fragment encoded in the android:name parameter.
430 */
431 @Override
432 public Header onGetInitialHeader() {
433 String fragmentClass = getStartingFragmentClass(super.getIntent());
434 if (fragmentClass != null) {
435 Header header = new Header();
436 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800437 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700438 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800439 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700440 return header;
441 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700442
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700443 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700444 }
445
Dianne Hackbornb7258182011-03-15 16:23:55 -0700446 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700447 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
448 int titleRes, int shortTitleRes) {
449 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
450 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700451
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800452 // Some fragments want split ActionBar; these should stay in sync with
453 // uiOptions for fragments also defined as activities in manifest.
454 if (WifiSettings.class.getName().equals(fragmentName) ||
455 WifiP2pSettings.class.getName().equals(fragmentName) ||
456 BluetoothSettings.class.getName().equals(fragmentName) ||
457 DreamSettings.class.getName().equals(fragmentName) ||
Lifu Tangd5fbbc42013-08-01 17:23:10 -0700458 LocationSettings.class.getName().equals(fragmentName) ||
Svetoslav2d531652013-09-03 21:32:40 -0700459 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
460 PrintSettingsFragment.class.getName().equals(fragmentName) ||
461 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800462 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700463 }
464
Dianne Hackbornb7258182011-03-15 16:23:55 -0700465 intent.setClass(this, SubSettings.class);
466 return intent;
467 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700468
Amith Yamasani379d9b02010-09-27 12:03:59 -0700469 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700470 * Populate the activity with the top-level headers.
471 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700472 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700473 public void onBuildHeaders(List<Header> headers) {
Amith Yamasani2972c012013-10-02 11:48:46 -0700474 if (!onIsHidingHeaders()) {
475 loadHeadersFromResource(R.xml.settings_headers, headers);
476 updateHeaderList(headers);
477 }
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700478 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700479
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700480 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700481 final boolean showDev = mDevelopmentPreferences.getBoolean(
482 DevelopmentSettings.PREF_SHOW,
483 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700484 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400485
486 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700487 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700488 while (i < target.size()) {
489 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700490 // Ids are integers, so downcasting
491 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400492 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700493 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700494 } else if (id == R.id.wifi_settings) {
495 // Remove WiFi Settings if WiFi service is not available.
496 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700497 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700498 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700499 } else if (id == R.id.bluetooth_settings) {
500 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700501 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700502 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700503 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700504 } else if (id == R.id.data_usage_settings) {
505 // Remove data usage when kernel module not enabled
506 final INetworkManagementService netManager = INetworkManagementService.Stub
507 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
508 try {
509 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700510 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700511 }
512 } catch (RemoteException e) {
513 // ignored
514 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900515 } else if (id == R.id.battery_settings) {
516 // Remove battery settings when battery is not available. (e.g. TV)
517
518 if (!mBatteryPresent) {
519 target.remove(i);
520 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700521 } else if (id == R.id.account_settings) {
522 int headerIndex = i + 1;
523 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700524 } else if (id == R.id.home_settings) {
Christopher Tate8243c9a2013-09-19 14:59:17 -0700525 if (!updateHomeSettingHeaders(header)) {
526 target.remove(i);
527 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700528 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700529 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700530 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700531 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700532 target.remove(i);
533 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700534 } else if (id == R.id.nfc_payment_settings) {
Martijn Coenen81ab8172013-09-30 12:07:02 -0700535 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
Martijn Coenen26515da2013-08-01 18:13:33 -0700536 target.remove(i);
Martijn Coenen81ab8172013-09-30 12:07:02 -0700537 } else {
538 // Only show if NFC is on and we have the HCE feature
539 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
540 if (!adapter.isEnabled() || !getPackageManager().hasSystemFeature(
541 PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
542 target.remove(i);
543 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700544 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700545 } else if (id == R.id.development_settings) {
546 if (!showDev) {
547 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700548 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400549 } else if (id == R.id.account_add) {
550 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
551 target.remove(i);
552 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700553 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700554
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900555 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700556 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700557 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700558 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700559 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700560
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700561 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900562 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800563 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700564 if (mFirstHeader == null &&
565 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
566 mFirstHeader = header;
567 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700568 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700569 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700570 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700571 }
572 }
573
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700574 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
575 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
576 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
577 for (String accountType : accountTypes) {
578 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700579 if (label == null) {
580 continue;
581 }
582
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700583 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
584 boolean skipToAccount = accounts.length == 1
585 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700586 Header accHeader = new Header();
587 accHeader.title = label;
588 if (accHeader.extras == null) {
589 accHeader.extras = new Bundle();
590 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700591 if (skipToAccount) {
592 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
593 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
594 accHeader.fragment = AccountSyncSettings.class.getName();
595 accHeader.fragmentArguments = new Bundle();
596 // Need this for the icon
597 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
598 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
599 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
600 accounts[0]);
601 } else {
602 accHeader.breadCrumbTitle = label;
603 accHeader.breadCrumbShortTitle = label;
604 accHeader.fragment = ManageAccountsSettings.class.getName();
605 accHeader.fragmentArguments = new Bundle();
606 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
607 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
608 accountType);
609 if (!isMultiPane()) {
610 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
611 label.toString());
612 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700613 }
614 accountHeaders.add(accHeader);
Amith Yamasani2972c012013-10-02 11:48:46 -0700615 mAuthenticatorHelper.preloadDrawableForType(this, accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700616 }
617
618 // Sort by label
619 Collections.sort(accountHeaders, new Comparator<Header>() {
620 @Override
621 public int compare(Header h1, Header h2) {
622 return h1.title.toString().compareTo(h2.title.toString());
623 }
624 });
625
626 for (Header header : accountHeaders) {
627 target.add(headerIndex++, header);
628 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700629 if (!mListeningToAccountUpdates) {
630 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
631 mListeningToAccountUpdates = true;
632 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700633 return headerIndex;
634 }
635
Christopher Tate8243c9a2013-09-19 14:59:17 -0700636 private boolean updateHomeSettingHeaders(Header header) {
Christopher Tatedc7be102013-10-08 11:30:19 -0700637 // Once we decide to show Home settings, keep showing it forever
638 SharedPreferences sp = getSharedPreferences(HomeSettings.HOME_PREFS, Context.MODE_PRIVATE);
639 if (sp.getBoolean(HomeSettings.HOME_PREFS_DO_SHOW, false)) {
640 return true;
641 }
642
Christopher Tatee238a472013-08-27 14:21:46 -0700643 try {
Jeff Sharkeyd572a032013-09-23 17:41:16 -0700644 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
645 getPackageManager().getHomeActivities(homeApps);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700646 if (homeApps.size() < 2) {
647 // When there's only one available home app, omit this settings
Christopher Tatee0d934f2013-10-01 12:32:27 -0700648 // category entirely at the top level UI. If the user just
649 // uninstalled the penultimate home app candidiate, we also
650 // now tell them about why they aren't seeing 'Home' in the list.
651 if (sShowNoHomeNotice) {
652 sShowNoHomeNotice = false;
653 NoHomeDialogFragment.show(this);
654 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700655 return false;
Christopher Tatee0d934f2013-10-01 12:32:27 -0700656 } else {
657 // Okay, we're allowing the Home settings category. Tell it, when
658 // invoked via this front door, that we'll need to be told about the
659 // case when the user uninstalls all but one home app.
660 if (header.fragmentArguments == null) {
661 header.fragmentArguments = new Bundle();
662 }
663 header.fragmentArguments.putBoolean(HomeSettings.HOME_SHOW_NOTICE, true);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700664 }
Christopher Tatee238a472013-08-27 14:21:46 -0700665 } catch (Exception e) {
666 // Can't look up the home activity; bail on configuring the icon
667 Log.w(LOG_TAG, "Problem looking up home activity!", e);
668 }
Christopher Tatedc7be102013-10-08 11:30:19 -0700669
670 sp.edit().putBoolean(HomeSettings.HOME_PREFS_DO_SHOW, true).apply();
Christopher Tate8243c9a2013-09-19 14:59:17 -0700671 return true;
Christopher Tatee238a472013-08-27 14:21:46 -0700672 }
673
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700674 private void getMetaData() {
675 try {
676 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
677 PackageManager.GET_META_DATA);
678 if (ai == null || ai.metaData == null) return;
679 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
680 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
681 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700682 // No recovery
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800683 Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString());
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700684 }
685 }
686
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800687 @Override
688 public boolean hasNextButton() {
689 return super.hasNextButton();
690 }
691
692 @Override
693 public Button getNextButton() {
694 return super.getNextButton();
695 }
696
Christopher Tatee0d934f2013-10-01 12:32:27 -0700697 public static class NoHomeDialogFragment extends DialogFragment {
698 public static void show(Activity parent) {
699 final NoHomeDialogFragment dialog = new NoHomeDialogFragment();
700 dialog.show(parent.getFragmentManager(), null);
701 }
702
703 @Override
704 public Dialog onCreateDialog(Bundle savedInstanceState) {
705 return new AlertDialog.Builder(getActivity())
706 .setMessage(R.string.only_one_home_message)
707 .setPositiveButton(android.R.string.ok, null)
708 .create();
709 }
710 }
711
Gilles Debunnee78c1872011-06-20 15:00:07 -0700712 private static class HeaderAdapter extends ArrayAdapter<Header> {
713 static final int HEADER_TYPE_CATEGORY = 0;
714 static final int HEADER_TYPE_NORMAL = 1;
715 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400716 static final int HEADER_TYPE_BUTTON = 3;
717 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700718
719 private final WifiEnabler mWifiEnabler;
720 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700721 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400722 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700723
724 private static class HeaderViewHolder {
725 ImageView icon;
726 TextView title;
727 TextView summary;
728 Switch switch_;
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800729 ImageButton button;
730 View divider;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700731 }
732
733 private LayoutInflater mInflater;
734
735 static int getHeaderType(Header header) {
736 if (header.fragment == null && header.intent == null) {
737 return HEADER_TYPE_CATEGORY;
738 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
739 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400740 } else if (header.id == R.id.security_settings) {
741 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700742 } else {
743 return HEADER_TYPE_NORMAL;
744 }
745 }
746
747 @Override
748 public int getItemViewType(int position) {
749 Header header = getItem(position);
750 return getHeaderType(header);
751 }
752
753 @Override
754 public boolean areAllItemsEnabled() {
755 return false; // because of categories
756 }
757
758 @Override
759 public boolean isEnabled(int position) {
760 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
761 }
762
763 @Override
764 public int getViewTypeCount() {
765 return HEADER_TYPE_COUNT;
766 }
767
768 @Override
769 public boolean hasStableIds() {
770 return true;
771 }
772
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700773 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400774 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700775 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700776
777 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700778 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700779
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700780 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700781 // Switches inflated from their layouts. Must be done before adapter is set in super
782 mWifiEnabler = new WifiEnabler(context, new Switch(context));
783 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400784 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700785 }
786
787 @Override
788 public View getView(int position, View convertView, ViewGroup parent) {
789 HeaderViewHolder holder;
790 Header header = getItem(position);
791 int headerType = getHeaderType(header);
792 View view = null;
793
794 if (convertView == null) {
795 holder = new HeaderViewHolder();
796 switch (headerType) {
797 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700798 view = new TextView(getContext(), null,
799 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700800 holder.title = (TextView) view;
801 break;
802
803 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700804 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
805 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700806 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700807 holder.title = (TextView)
808 view.findViewById(com.android.internal.R.id.title);
809 holder.summary = (TextView)
810 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700811 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
812 break;
813
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400814 case HEADER_TYPE_BUTTON:
815 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
816 false);
817 holder.icon = (ImageView) view.findViewById(R.id.icon);
818 holder.title = (TextView)
819 view.findViewById(com.android.internal.R.id.title);
820 holder.summary = (TextView)
821 view.findViewById(com.android.internal.R.id.summary);
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800822 holder.button = (ImageButton) view.findViewById(R.id.buttonWidget);
823 holder.divider = view.findViewById(R.id.divider);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400824 break;
825
Gilles Debunnee78c1872011-06-20 15:00:07 -0700826 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700827 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700828 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700829 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700830 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700831 holder.title = (TextView)
832 view.findViewById(com.android.internal.R.id.title);
833 holder.summary = (TextView)
834 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700835 break;
836 }
837 view.setTag(holder);
838 } else {
839 view = convertView;
840 holder = (HeaderViewHolder) view.getTag();
841 }
842
843 // All view fields must be updated every time, because the view may be recycled
844 switch (headerType) {
845 case HEADER_TYPE_CATEGORY:
846 holder.title.setText(header.getTitle(getContext().getResources()));
847 break;
848
849 case HEADER_TYPE_SWITCH:
850 // Would need a different treatment if the main menu had more switches
851 if (header.id == R.id.wifi_settings) {
852 mWifiEnabler.setSwitch(holder.switch_);
853 } else {
854 mBluetoothEnabler.setSwitch(holder.switch_);
855 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400856 updateCommonHeaderView(header, holder);
857 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700858
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400859 case HEADER_TYPE_BUTTON:
860 if (header.id == R.id.security_settings) {
861 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
862 if (hasCert) {
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800863 holder.button.setVisibility(View.VISIBLE);
864 holder.divider.setVisibility(View.VISIBLE);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400865 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
866 if (isManaged) {
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800867 holder.button.setImageResource(R.drawable.ic_settings_about);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400868 } else {
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800869 holder.button.setImageResource(
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400870 android.R.drawable.stat_notify_error);
871 }
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800872 holder.button.setOnClickListener(new OnClickListener() {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400873 @Override
874 public void onClick(View v) {
875 Intent intent = new Intent(
876 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
877 getContext().startActivity(intent);
878 }
879 });
880 } else {
Fabrice Di Meglioad38a882014-01-14 13:57:44 -0800881 holder.button.setVisibility(View.GONE);
882 holder.divider.setVisibility(View.GONE);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400883 }
884 }
885 updateCommonHeaderView(header, holder);
886 break;
887
Gilles Debunnee78c1872011-06-20 15:00:07 -0700888 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400889 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700890 break;
891 }
892
893 return view;
894 }
895
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400896 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
897 if (header.extras != null
898 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
899 String accType = header.extras.getString(
900 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
901 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
902 setHeaderIcon(holder, icon);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400903 } else {
904 holder.icon.setImageResource(header.iconRes);
905 }
906 holder.title.setText(header.getTitle(getContext().getResources()));
907 CharSequence summary = header.getSummary(getContext().getResources());
908 if (!TextUtils.isEmpty(summary)) {
909 holder.summary.setVisibility(View.VISIBLE);
910 holder.summary.setText(summary);
911 } else {
912 holder.summary.setVisibility(View.GONE);
913 }
914 }
915
Christopher Tatee238a472013-08-27 14:21:46 -0700916 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
917 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
918 lp.width = getContext().getResources().getDimensionPixelSize(
919 R.dimen.header_icon_width);
920 lp.height = lp.width;
921 holder.icon.setLayoutParams(lp);
922 holder.icon.setImageDrawable(icon);
923 }
924
Gilles Debunnee78c1872011-06-20 15:00:07 -0700925 public void resume() {
926 mWifiEnabler.resume();
927 mBluetoothEnabler.resume();
928 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700929
Gilles Debunnee78c1872011-06-20 15:00:07 -0700930 public void pause() {
931 mWifiEnabler.pause();
932 mBluetoothEnabler.pause();
933 }
934 }
935
936 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700937 public void onHeaderClick(Header header, int position) {
938 boolean revert = false;
939 if (header.id == R.id.account_add) {
940 revert = true;
941 }
942
943 super.onHeaderClick(header, position);
944
945 if (revert && mLastHeader != null) {
946 highlightHeader((int) mLastHeader.id);
947 } else {
948 mLastHeader = header;
949 }
950 }
951
952 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700953 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
954 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800955 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700956 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800957 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -0700958 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
959 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -0700960 if (UserManager.get(this).isLinkedUser()) {
961 titleRes = R.string.profile_info_settings_title;
962 } else {
963 titleRes = R.string.user_info_settings_title;
964 }
Amith Yamasania4379d62011-07-22 10:34:58 -0700965 }
Jean Chalard7dabe452012-05-10 18:08:07 +0900966 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
967 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -0700968 return true;
969 }
970
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400971 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -0700972 public boolean shouldUpRecreateTask(Intent targetIntent) {
973 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
974 }
975
Amith Yamasania4379d62011-07-22 10:34:58 -0700976 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700977 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700978 if (adapter == null) {
979 super.setListAdapter(null);
980 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400981 DevicePolicyManager dpm =
982 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
983 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700984 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700985 }
986
Amith Yamasani56821db2012-06-05 13:20:45 -0700987 @Override
988 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -0700989 // TODO: watch for package upgrades to invalidate cache; see 7206643
990 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -0700991 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
992 invalidateHeaders();
993 }
994
Christopher Tatee0d934f2013-10-01 12:32:27 -0700995 public static void requestHomeNotice() {
996 sShowNoHomeNotice = true;
997 }
998
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700999 /*
1000 * Settings subclasses for launching independently.
1001 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001002 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1003 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1004 public static class TetherSettingsActivity extends Settings { /* empty */ }
1005 public static class VpnSettingsActivity extends Settings { /* empty */ }
1006 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1007 public static class StorageSettingsActivity extends Settings { /* empty */ }
1008 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001009 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001010 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001011 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001012 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001013 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001014 public static class LocalePickerActivity extends Settings { /* empty */ }
1015 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1016 public static class SoundSettingsActivity extends Settings { /* empty */ }
1017 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1018 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1019 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1020 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Amith Yamasania88bdd32013-11-25 11:10:00 -08001021 public static class AppOpsSummaryActivity extends Settings {
1022 @Override
1023 public boolean isValidFragment(String className) {
1024 if (AppOpsSummary.class.getName().equals(className)) {
1025 return true;
1026 }
1027 return super.isValidFragment(className);
1028 }
1029 }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001030 public static class StorageUseActivity extends Settings { /* empty */ }
1031 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1032 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001033 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Alan Viverettefc0ab212013-10-02 16:36:33 -07001034 public static class AccessibilityInversionSettingsActivity extends Settings { /* empty */ }
1035 public static class AccessibilityContrastSettingsActivity extends Settings { /* empty */ }
1036 public static class AccessibilityDaltonizerSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001037 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001038 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001039 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001040 public static class RunningServicesActivity extends Settings { /* empty */ }
1041 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1042 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1043 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1044 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1045 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1046 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1047 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001048 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001049 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001050 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001051 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001052 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001053 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001054 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001055 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001056 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001057 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001058 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001059 public static class PrintSettingsActivity extends Settings { /* empty */ }
Svetoslavd9f156d2013-10-09 21:59:04 -07001060 public static class PrintJobSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001061}