blob: 13f71665e1669f1efe6f449f8625ec26ee7ab6b3 [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;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -040022import android.app.admin.DevicePolicyManager;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090023import android.content.BroadcastReceiver;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080024import android.content.ComponentName;
Gilles Debunnee78c1872011-06-20 15:00:07 -070025import android.content.Context;
Amith Yamasani379d9b02010-09-27 12:03:59 -070026import android.content.Intent;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090027import android.content.IntentFilter;
Dianne Hackborncaefa9b2012-10-10 15:05:42 -070028import android.content.SharedPreferences;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070029import android.content.pm.ActivityInfo;
Christopher Tatee238a472013-08-27 14:21:46 -070030import android.content.pm.ApplicationInfo;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070031import android.content.pm.PackageManager;
32import android.content.pm.PackageManager.NameNotFoundException;
Christopher Tatee238a472013-08-27 14:21:46 -070033import android.content.pm.ResolveInfo;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070034import android.graphics.drawable.Drawable;
Martijn Coenen81ab8172013-09-30 12:07:02 -070035import android.nfc.NfcAdapter;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070036import android.os.Bundle;
Jeff Sharkey34e964d2012-04-21 15:41:48 -070037import android.os.INetworkManagementService;
38import android.os.RemoteException;
39import android.os.ServiceManager;
Dianne Hackbornbb06a422012-08-16 11:01:57 -070040import android.os.UserHandle;
Jeff Sharkey44202462012-09-19 13:13:45 -070041import android.os.UserManager;
Amith Yamasania4379d62011-07-22 10:34:58 -070042import android.preference.Preference;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070043import android.preference.PreferenceActivity;
Amith Yamasania4379d62011-07-22 10:34:58 -070044import android.preference.PreferenceFragment;
Gilles Debunnee78c1872011-06-20 15:00:07 -070045import android.text.TextUtils;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080046import android.util.Log;
Gilles Debunnee78c1872011-06-20 15:00:07 -070047import android.view.LayoutInflater;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080048import android.view.View;
49import android.view.View.OnClickListener;
Gilles Debunnee78c1872011-06-20 15:00:07 -070050import android.view.ViewGroup;
51import android.widget.ArrayAdapter;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080052import android.widget.Button;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -040053import android.widget.ImageButton;
Gilles Debunnee78c1872011-06-20 15:00:07 -070054import android.widget.ImageView;
55import android.widget.ListAdapter;
56import android.widget.Switch;
57import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080058
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080059import com.android.internal.util.ArrayUtils;
Amith Yamasania677ee22013-07-26 13:38:41 -070060import com.android.settings.accessibility.AccessibilitySettings;
Alan Viverette341ff662013-07-18 17:49:33 -070061import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
Alan Viverette9b625f02013-09-11 13:03:14 -070062import com.android.settings.accessibility.ToggleCaptioningPreferenceFragment;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080063import com.android.settings.accounts.AccountSyncSettings;
64import com.android.settings.accounts.AuthenticatorHelper;
65import com.android.settings.accounts.ManageAccountsSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070066import com.android.settings.applications.AppOpsSummary;
67import com.android.settings.applications.ManageApplications;
Dianne Hackbornc6d658e2013-08-08 12:57:53 -070068import com.android.settings.applications.ProcessStatsUi;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080069import com.android.settings.bluetooth.BluetoothEnabler;
70import com.android.settings.bluetooth.BluetoothSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070071import com.android.settings.deviceinfo.Memory;
72import com.android.settings.deviceinfo.UsbSettings;
73import com.android.settings.fuelgauge.PowerUsageSummary;
74import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
Amith Yamasani3a14ae22013-08-30 15:43:44 -070075import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070076import com.android.settings.inputmethod.SpellCheckersSettings;
77import com.android.settings.inputmethod.UserDictionaryList;
Amith Yamasanie9904202013-08-01 10:26:14 -070078import com.android.settings.location.LocationSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070079import com.android.settings.nfc.AndroidBeam;
Martijn Coenen53083ab2013-08-09 13:37:38 -070080import com.android.settings.nfc.PaymentSettings;
Svetoslav2d531652013-09-03 21:32:40 -070081import com.android.settings.print.PrintServiceSettingsFragment;
82import com.android.settings.print.PrintSettingsFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070083import com.android.settings.tts.TextToSpeechSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070084import com.android.settings.users.UserSettings;
85import com.android.settings.vpn2.VpnSettings;
Jeff Sharkey0c3634c2013-02-20 12:35:16 -080086import com.android.settings.wfd.WifiDisplaySettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070087import com.android.settings.wifi.AdvancedWifiSettings;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080088import com.android.settings.wifi.WifiEnabler;
89import com.android.settings.wifi.WifiSettings;
90import com.android.settings.wifi.p2p.WifiP2pSettings;
91
Gilles Debunnee78c1872011-06-20 15:00:07 -070092import java.util.ArrayList;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070093import java.util.Collections;
94import java.util.Comparator;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070095import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070096import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -070097
98/**
99 * Top-level settings activity to handle single pane and double pane UI layout.
100 */
Amith Yamasani56821db2012-06-05 13:20:45 -0700101public class Settings extends PreferenceActivity
102 implements ButtonBarHandler, OnAccountsUpdateListener {
Amith Yamasanid7993472010-08-18 13:59:28 -0700103
Gilles Debunnee78c1872011-06-20 15:00:07 -0700104 private static final String LOG_TAG = "Settings";
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700105
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700106 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700107 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700108 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700109 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800110 private static final String META_DATA_KEY_PARENT_TITLE =
111 "com.android.settings.PARENT_FRAGMENT_TITLE";
112 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
113 "com.android.settings.PARENT_FRAGMENT_CLASS";
114
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800115 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700116
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800117 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
118 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700119
120 private String mFragmentClass;
121 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -0800122 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800123 private Header mCurrentHeader;
124 private Header mParentHeader;
125 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700126
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700127 // Show only these settings for restricted users
128 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700129 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700130 R.id.wifi_settings,
131 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700132 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700133 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700134 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700135 R.id.sound_settings,
136 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700137 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700138 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700139 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700140 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700141 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700142 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700143 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700144 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700145 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700146 R.id.account_add,
147 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700148 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700149 R.id.about_settings,
Svetoslav Ganovd4c7b492013-06-11 21:15:11 -0700150 R.id.accessibility_settings,
Martijn Coenen26515da2013-08-01 18:13:33 -0700151 R.id.print_settings,
Christopher Tatee238a472013-08-27 14:21:46 -0700152 R.id.nfc_payment_settings,
153 R.id.home_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700154 };
155
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700156 private SharedPreferences mDevelopmentPreferences;
157 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
158
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700159 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700160
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700161 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
162
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700163 private AuthenticatorHelper mAuthenticatorHelper;
164 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700165 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700166
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900167 private boolean mBatteryPresent = true;
168 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
169
170 @Override
171 public void onReceive(Context context, Intent intent) {
172 String action = intent.getAction();
173 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
174 boolean batteryPresent = Utils.isBatteryPresent(intent);
175
176 if (mBatteryPresent != batteryPresent) {
177 mBatteryPresent = batteryPresent;
178 invalidateHeaders();
179 }
180 }
181 }
182 };
183
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700184 @Override
185 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800186 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
187 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700188 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700189
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700190 mAuthenticatorHelper = new AuthenticatorHelper();
191 mAuthenticatorHelper.updateAuthDescriptions(this);
192 mAuthenticatorHelper.onAccountsUpdated(this, null);
193
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700194 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
195 Context.MODE_PRIVATE);
196
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700197 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800198 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700199 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800200 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700201
Gilles Debunne3661b622011-06-27 11:19:16 -0700202 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700203 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800204 // Force the title so that it doesn't get overridden by a direct launch of
205 // a specific settings screen.
206 setTitle(R.string.settings_label);
207 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800208
209 // Retrieve any saved state
210 if (savedInstanceState != null) {
211 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
212 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
213 }
214
215 // If the current header was saved, switch to it
216 if (savedInstanceState != null && mCurrentHeader != null) {
217 //switchToHeaderLocal(mCurrentHeader);
218 showBreadCrumbs(mCurrentHeader.title, null);
219 }
220
221 if (mParentHeader != null) {
222 setParentTitle(mParentHeader.title, null, new OnClickListener() {
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400223 @Override
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800224 public void onClick(View v) {
225 switchToParent(mParentHeader.fragment);
226 }
227 });
228 }
Gilles Debunnedc7101f2011-06-27 12:00:49 -0700229
Amith Yamasani3d384f42012-05-11 15:22:04 -0700230 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
231 if (onIsMultiPane()) {
232 getActionBar().setDisplayHomeAsUpEnabled(false);
233 getActionBar().setHomeButtonEnabled(false);
234 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800235 }
236
237 @Override
238 protected void onSaveInstanceState(Bundle outState) {
239 super.onSaveInstanceState(outState);
240
241 // Save the current fragment, if it is the same as originally launched
242 if (mCurrentHeader != null) {
243 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
244 }
245 if (mParentHeader != null) {
246 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
247 }
248 }
249
Gilles Debunnee78c1872011-06-20 15:00:07 -0700250 @Override
251 public void onResume() {
252 super.onResume();
253
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700254 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
255 @Override
256 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
257 invalidateHeaders();
258 }
259 };
260 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
261 mDevelopmentPreferencesListener);
262
Gilles Debunnee78c1872011-06-20 15:00:07 -0700263 ListAdapter listAdapter = getListAdapter();
264 if (listAdapter instanceof HeaderAdapter) {
265 ((HeaderAdapter) listAdapter).resume();
266 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700267 invalidateHeaders();
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900268
269 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700270 }
271
272 @Override
273 public void onPause() {
274 super.onPause();
275
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900276 unregisterReceiver(mBatteryInfoReceiver);
277
Gilles Debunnee78c1872011-06-20 15:00:07 -0700278 ListAdapter listAdapter = getListAdapter();
279 if (listAdapter instanceof HeaderAdapter) {
280 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700281 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700282
283 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
284 mDevelopmentPreferencesListener);
285 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700286 }
287
288 @Override
289 public void onDestroy() {
290 super.onDestroy();
291 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700292 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700293 }
294 }
295
Amith Yamasani56f51a82013-08-05 10:07:23 -0700296 @Override
297 public boolean onIsMultiPane() {
298 return false;
299 }
300
Amith Yamasania677ee22013-07-26 13:38:41 -0700301 private static final String[] ENTRY_FRAGMENTS = {
302 WirelessSettings.class.getName(),
303 WifiSettings.class.getName(),
304 AdvancedWifiSettings.class.getName(),
305 BluetoothSettings.class.getName(),
306 TetherSettings.class.getName(),
307 WifiP2pSettings.class.getName(),
308 VpnSettings.class.getName(),
309 DateTimeSettings.class.getName(),
310 LocalePicker.class.getName(),
311 InputMethodAndLanguageSettings.class.getName(),
312 SpellCheckersSettings.class.getName(),
313 UserDictionaryList.class.getName(),
314 UserDictionarySettings.class.getName(),
315 SoundSettings.class.getName(),
316 DisplaySettings.class.getName(),
317 DeviceInfoSettings.class.getName(),
318 ManageApplications.class.getName(),
Dianne Hackbornc6d658e2013-08-08 12:57:53 -0700319 ProcessStatsUi.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700320 NotificationStation.class.getName(),
321 AppOpsSummary.class.getName(),
322 LocationSettings.class.getName(),
323 SecuritySettings.class.getName(),
324 PrivacySettings.class.getName(),
325 DeviceAdminSettings.class.getName(),
326 AccessibilitySettings.class.getName(),
Alan Viverette9b625f02013-09-11 13:03:14 -0700327 ToggleCaptioningPreferenceFragment.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700328 TextToSpeechSettings.class.getName(),
329 Memory.class.getName(),
330 DevelopmentSettings.class.getName(),
331 UsbSettings.class.getName(),
332 AndroidBeam.class.getName(),
333 WifiDisplaySettings.class.getName(),
334 PowerUsageSummary.class.getName(),
335 AccountSyncSettings.class.getName(),
336 CryptKeeperSettings.class.getName(),
337 DataUsageSummary.class.getName(),
338 DreamSettings.class.getName(),
339 UserSettings.class.getName(),
340 NotificationAccessSettings.class.getName(),
Amith Yamasaniee226f92013-08-05 11:02:16 -0700341 ManageAccountsSettings.class.getName(),
Svetoslav2d531652013-09-03 21:32:40 -0700342 PrintSettingsFragment.class.getName(),
Martijn Coenen53083ab2013-08-09 13:37:38 -0700343 TrustedCredentialsSettings.class.getName(),
Amith Yamasani3a14ae22013-08-30 15:43:44 -0700344 PaymentSettings.class.getName(),
345 KeyboardLayoutPickerFragment.class.getName()
Amith Yamasania677ee22013-07-26 13:38:41 -0700346 };
347
348 @Override
349 protected boolean isValidFragment(String fragmentName) {
350 // Almost all fragments are wrapped in this,
351 // except for a few that have their own activities.
352 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
353 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
354 }
355 return false;
356 }
357
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800358 private void switchToHeaderLocal(Header header) {
359 mInLocalHeaderSwitch = true;
360 switchToHeader(header);
361 mInLocalHeaderSwitch = false;
362 }
363
364 @Override
365 public void switchToHeader(Header header) {
366 if (!mInLocalHeaderSwitch) {
367 mCurrentHeader = null;
368 mParentHeader = null;
369 }
370 super.switchToHeader(header);
371 }
372
373 /**
374 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800375 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800376 */
377 private void switchToParent(String className) {
378 final ComponentName cn = new ComponentName(this, className);
379 try {
380 final PackageManager pm = getPackageManager();
381 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
382
383 if (parentInfo != null && parentInfo.metaData != null) {
384 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
385 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
386 Header parentHeader = new Header();
387 parentHeader.fragment = fragmentClass;
388 parentHeader.title = fragmentTitle;
389 mCurrentHeader = parentHeader;
390
391 switchToHeaderLocal(parentHeader);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700392 highlightHeader(mTopLevelHeaderId);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800393
394 mParentHeader = new Header();
395 mParentHeader.fragment
396 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
397 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
398 }
399 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700400 Log.w(LOG_TAG, "Could not find parent activity : " + className);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800401 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700402 }
403
Amith Yamasani3965ae62010-11-15 14:45:19 -0800404 @Override
405 public void onNewIntent(Intent intent) {
406 super.onNewIntent(intent);
407
408 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700409 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
410 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
411 switchToHeaderLocal(mFirstHeader);
412 }
413 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800414 }
415 }
416
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700417 private void highlightHeader(int id) {
418 if (id != 0) {
419 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700420 if (index != null) {
421 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700422 if (isMultiPane()) {
423 getListView().smoothScrollToPosition(index);
424 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700425 }
426 }
427 }
428
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700429 @Override
430 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700431 Intent superIntent = super.getIntent();
432 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700433 // This is called from super.onCreate, isMultiPane() is not yet reliable
434 // Do not use onIsHidingHeaders either, which relies itself on this method
435 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700436 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700437 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700438 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700439 if (args != null) {
440 args = new Bundle(args);
441 } else {
442 args = new Bundle();
443 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700444 args.putParcelable("intent", superIntent);
445 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700446 return modIntent;
447 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700448 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700449 }
450
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700451 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700452 * Checks if the component name in the intent is different from the Settings class and
453 * returns the class name to load as a fragment.
454 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700455 protected String getStartingFragmentClass(Intent intent) {
456 if (mFragmentClass != null) return mFragmentClass;
457
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700458 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700459 if (intentClass.equals(getClass().getName())) return null;
460
Dianne Hackbornee293792010-11-01 12:32:33 -0700461 if ("com.android.settings.ManageApplications".equals(intentClass)
462 || "com.android.settings.RunningServices".equals(intentClass)
463 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700464 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700465 intentClass = com.android.settings.applications.ManageApplications.class.getName();
466 }
467
Amith Yamasani379d9b02010-09-27 12:03:59 -0700468 return intentClass;
469 }
470
471 /**
472 * Override initial header when an activity-alias is causing Settings to be launched
473 * for a specific fragment encoded in the android:name parameter.
474 */
475 @Override
476 public Header onGetInitialHeader() {
477 String fragmentClass = getStartingFragmentClass(super.getIntent());
478 if (fragmentClass != null) {
479 Header header = new Header();
480 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800481 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700482 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800483 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700484 return header;
485 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700486
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700487 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700488 }
489
Dianne Hackbornb7258182011-03-15 16:23:55 -0700490 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700491 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
492 int titleRes, int shortTitleRes) {
493 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
494 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700495
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800496 // Some fragments want split ActionBar; these should stay in sync with
497 // uiOptions for fragments also defined as activities in manifest.
498 if (WifiSettings.class.getName().equals(fragmentName) ||
499 WifiP2pSettings.class.getName().equals(fragmentName) ||
Jeff Sharkey0c3634c2013-02-20 12:35:16 -0800500 WifiDisplaySettings.class.getName().equals(fragmentName) ||
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800501 BluetoothSettings.class.getName().equals(fragmentName) ||
502 DreamSettings.class.getName().equals(fragmentName) ||
Lifu Tangd5fbbc42013-08-01 17:23:10 -0700503 LocationSettings.class.getName().equals(fragmentName) ||
Svetoslav2d531652013-09-03 21:32:40 -0700504 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
505 PrintSettingsFragment.class.getName().equals(fragmentName) ||
506 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800507 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700508 }
509
Dianne Hackbornb7258182011-03-15 16:23:55 -0700510 intent.setClass(this, SubSettings.class);
511 return intent;
512 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700513
Amith Yamasani379d9b02010-09-27 12:03:59 -0700514 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700515 * Populate the activity with the top-level headers.
516 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700517 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700518 public void onBuildHeaders(List<Header> headers) {
519 loadHeadersFromResource(R.xml.settings_headers, headers);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700520 updateHeaderList(headers);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700521 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700522
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700523 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700524 final boolean showDev = mDevelopmentPreferences.getBoolean(
525 DevelopmentSettings.PREF_SHOW,
526 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700527 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400528
529 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700530 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700531 while (i < target.size()) {
532 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700533 // Ids are integers, so downcasting
534 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400535 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700536 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700537 } else if (id == R.id.wifi_settings) {
538 // Remove WiFi Settings if WiFi service is not available.
539 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700540 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700541 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700542 } else if (id == R.id.bluetooth_settings) {
543 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700544 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700545 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700546 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700547 } else if (id == R.id.data_usage_settings) {
548 // Remove data usage when kernel module not enabled
549 final INetworkManagementService netManager = INetworkManagementService.Stub
550 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
551 try {
552 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700553 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700554 }
555 } catch (RemoteException e) {
556 // ignored
557 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900558 } else if (id == R.id.battery_settings) {
559 // Remove battery settings when battery is not available. (e.g. TV)
560
561 if (!mBatteryPresent) {
562 target.remove(i);
563 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700564 } else if (id == R.id.account_settings) {
565 int headerIndex = i + 1;
566 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700567 } else if (id == R.id.home_settings) {
Christopher Tate8243c9a2013-09-19 14:59:17 -0700568 if (!updateHomeSettingHeaders(header)) {
569 target.remove(i);
570 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700571 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700572 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700573 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700574 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700575 target.remove(i);
576 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700577 } else if (id == R.id.nfc_payment_settings) {
Martijn Coenen81ab8172013-09-30 12:07:02 -0700578 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
Martijn Coenen26515da2013-08-01 18:13:33 -0700579 target.remove(i);
Martijn Coenen81ab8172013-09-30 12:07:02 -0700580 } else {
581 // Only show if NFC is on and we have the HCE feature
582 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
583 if (!adapter.isEnabled() || !getPackageManager().hasSystemFeature(
584 PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
585 target.remove(i);
586 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700587 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700588 } else if (id == R.id.development_settings) {
589 if (!showDev) {
590 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700591 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400592 } else if (id == R.id.account_add) {
593 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
594 target.remove(i);
595 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700596 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700597
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900598 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700599 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700600 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700601 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700602 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700603
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700604 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900605 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800606 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700607 if (mFirstHeader == null &&
608 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
609 mFirstHeader = header;
610 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700611 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700612 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700613 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700614 }
615 }
616
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700617 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
618 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
619 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
620 for (String accountType : accountTypes) {
621 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700622 if (label == null) {
623 continue;
624 }
625
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700626 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
627 boolean skipToAccount = accounts.length == 1
628 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700629 Header accHeader = new Header();
630 accHeader.title = label;
631 if (accHeader.extras == null) {
632 accHeader.extras = new Bundle();
633 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700634 if (skipToAccount) {
635 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
636 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
637 accHeader.fragment = AccountSyncSettings.class.getName();
638 accHeader.fragmentArguments = new Bundle();
639 // Need this for the icon
640 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
641 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
642 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
643 accounts[0]);
644 } else {
645 accHeader.breadCrumbTitle = label;
646 accHeader.breadCrumbShortTitle = label;
647 accHeader.fragment = ManageAccountsSettings.class.getName();
648 accHeader.fragmentArguments = new Bundle();
649 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
650 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
651 accountType);
652 if (!isMultiPane()) {
653 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
654 label.toString());
655 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700656 }
657 accountHeaders.add(accHeader);
658 }
659
660 // Sort by label
661 Collections.sort(accountHeaders, new Comparator<Header>() {
662 @Override
663 public int compare(Header h1, Header h2) {
664 return h1.title.toString().compareTo(h2.title.toString());
665 }
666 });
667
668 for (Header header : accountHeaders) {
669 target.add(headerIndex++, header);
670 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700671 if (!mListeningToAccountUpdates) {
672 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
673 mListeningToAccountUpdates = true;
674 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700675 return headerIndex;
676 }
677
Christopher Tate8243c9a2013-09-19 14:59:17 -0700678 private boolean updateHomeSettingHeaders(Header header) {
Christopher Tatee238a472013-08-27 14:21:46 -0700679 try {
Jeff Sharkeyd572a032013-09-23 17:41:16 -0700680 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
681 getPackageManager().getHomeActivities(homeApps);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700682 if (homeApps.size() < 2) {
683 // When there's only one available home app, omit this settings
684 // category entirely at the top level UI.
685 return false;
686 }
Christopher Tatee238a472013-08-27 14:21:46 -0700687 } catch (Exception e) {
688 // Can't look up the home activity; bail on configuring the icon
689 Log.w(LOG_TAG, "Problem looking up home activity!", e);
690 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700691 return true;
Christopher Tatee238a472013-08-27 14:21:46 -0700692 }
693
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700694 private void getMetaData() {
695 try {
696 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
697 PackageManager.GET_META_DATA);
698 if (ai == null || ai.metaData == null) return;
699 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
700 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700701
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800702 // Check if it has a parent specified and create a Header object
703 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
704 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
705 if (parentFragmentClass != null) {
706 mParentHeader = new Header();
707 mParentHeader.fragment = parentFragmentClass;
708 if (parentHeaderTitleRes != 0) {
709 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
710 }
711 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700712 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700713 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700714 }
715 }
716
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800717 @Override
718 public boolean hasNextButton() {
719 return super.hasNextButton();
720 }
721
722 @Override
723 public Button getNextButton() {
724 return super.getNextButton();
725 }
726
Gilles Debunnee78c1872011-06-20 15:00:07 -0700727 private static class HeaderAdapter extends ArrayAdapter<Header> {
728 static final int HEADER_TYPE_CATEGORY = 0;
729 static final int HEADER_TYPE_NORMAL = 1;
730 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400731 static final int HEADER_TYPE_BUTTON = 3;
732 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700733
734 private final WifiEnabler mWifiEnabler;
735 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700736 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400737 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700738
739 private static class HeaderViewHolder {
740 ImageView icon;
741 TextView title;
742 TextView summary;
743 Switch switch_;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400744 ImageButton button_;
745 View divider_;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700746 }
747
748 private LayoutInflater mInflater;
749
750 static int getHeaderType(Header header) {
751 if (header.fragment == null && header.intent == null) {
752 return HEADER_TYPE_CATEGORY;
753 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
754 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400755 } else if (header.id == R.id.security_settings) {
756 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700757 } else {
758 return HEADER_TYPE_NORMAL;
759 }
760 }
761
762 @Override
763 public int getItemViewType(int position) {
764 Header header = getItem(position);
765 return getHeaderType(header);
766 }
767
768 @Override
769 public boolean areAllItemsEnabled() {
770 return false; // because of categories
771 }
772
773 @Override
774 public boolean isEnabled(int position) {
775 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
776 }
777
778 @Override
779 public int getViewTypeCount() {
780 return HEADER_TYPE_COUNT;
781 }
782
783 @Override
784 public boolean hasStableIds() {
785 return true;
786 }
787
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700788 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400789 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700790 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700791
792 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700793 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700794
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700795 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700796 // Switches inflated from their layouts. Must be done before adapter is set in super
797 mWifiEnabler = new WifiEnabler(context, new Switch(context));
798 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400799 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700800 }
801
802 @Override
803 public View getView(int position, View convertView, ViewGroup parent) {
804 HeaderViewHolder holder;
805 Header header = getItem(position);
806 int headerType = getHeaderType(header);
807 View view = null;
808
809 if (convertView == null) {
810 holder = new HeaderViewHolder();
811 switch (headerType) {
812 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700813 view = new TextView(getContext(), null,
814 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700815 holder.title = (TextView) view;
816 break;
817
818 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700819 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
820 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700821 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700822 holder.title = (TextView)
823 view.findViewById(com.android.internal.R.id.title);
824 holder.summary = (TextView)
825 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700826 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
827 break;
828
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400829 case HEADER_TYPE_BUTTON:
830 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
831 false);
832 holder.icon = (ImageView) view.findViewById(R.id.icon);
833 holder.title = (TextView)
834 view.findViewById(com.android.internal.R.id.title);
835 holder.summary = (TextView)
836 view.findViewById(com.android.internal.R.id.summary);
837 holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget);
838 holder.divider_ = view.findViewById(R.id.divider);
839 break;
840
Gilles Debunnee78c1872011-06-20 15:00:07 -0700841 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700842 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700843 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700844 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700845 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700846 holder.title = (TextView)
847 view.findViewById(com.android.internal.R.id.title);
848 holder.summary = (TextView)
849 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700850 break;
851 }
852 view.setTag(holder);
853 } else {
854 view = convertView;
855 holder = (HeaderViewHolder) view.getTag();
856 }
857
858 // All view fields must be updated every time, because the view may be recycled
859 switch (headerType) {
860 case HEADER_TYPE_CATEGORY:
861 holder.title.setText(header.getTitle(getContext().getResources()));
862 break;
863
864 case HEADER_TYPE_SWITCH:
865 // Would need a different treatment if the main menu had more switches
866 if (header.id == R.id.wifi_settings) {
867 mWifiEnabler.setSwitch(holder.switch_);
868 } else {
869 mBluetoothEnabler.setSwitch(holder.switch_);
870 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400871 updateCommonHeaderView(header, holder);
872 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700873
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400874 case HEADER_TYPE_BUTTON:
875 if (header.id == R.id.security_settings) {
876 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
877 if (hasCert) {
878 holder.button_.setVisibility(View.VISIBLE);
879 holder.divider_.setVisibility(View.VISIBLE);
880 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
881 if (isManaged) {
882 holder.button_.setImageResource(R.drawable.ic_qs_certificate_info);
883 } else {
884 holder.button_.setImageResource(
885 android.R.drawable.stat_notify_error);
886 }
887 holder.button_.setOnClickListener(new OnClickListener() {
888 @Override
889 public void onClick(View v) {
890 Intent intent = new Intent(
891 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
892 getContext().startActivity(intent);
893 }
894 });
895 } else {
896 holder.button_.setVisibility(View.GONE);
897 holder.divider_.setVisibility(View.GONE);
898 }
899 }
900 updateCommonHeaderView(header, holder);
901 break;
902
Gilles Debunnee78c1872011-06-20 15:00:07 -0700903 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400904 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700905 break;
906 }
907
908 return view;
909 }
910
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400911 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
912 if (header.extras != null
913 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
914 String accType = header.extras.getString(
915 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
916 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
917 setHeaderIcon(holder, icon);
918 } else if (header.extras != null &&
919 header.extras.containsKey(HomeSettings.CURRENT_HOME)) {
920 ActivityInfo ai = header.extras.getParcelable(HomeSettings.CURRENT_HOME);
921 Drawable icon = ai.loadIcon(getContext().getPackageManager());
922 setHeaderIcon(holder, icon);
923 } else {
924 holder.icon.setImageResource(header.iconRes);
925 }
926 holder.title.setText(header.getTitle(getContext().getResources()));
927 CharSequence summary = header.getSummary(getContext().getResources());
928 if (!TextUtils.isEmpty(summary)) {
929 holder.summary.setVisibility(View.VISIBLE);
930 holder.summary.setText(summary);
931 } else {
932 holder.summary.setVisibility(View.GONE);
933 }
934 }
935
Christopher Tatee238a472013-08-27 14:21:46 -0700936 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
937 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
938 lp.width = getContext().getResources().getDimensionPixelSize(
939 R.dimen.header_icon_width);
940 lp.height = lp.width;
941 holder.icon.setLayoutParams(lp);
942 holder.icon.setImageDrawable(icon);
943 }
944
Gilles Debunnee78c1872011-06-20 15:00:07 -0700945 public void resume() {
946 mWifiEnabler.resume();
947 mBluetoothEnabler.resume();
948 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700949
Gilles Debunnee78c1872011-06-20 15:00:07 -0700950 public void pause() {
951 mWifiEnabler.pause();
952 mBluetoothEnabler.pause();
953 }
954 }
955
956 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700957 public void onHeaderClick(Header header, int position) {
958 boolean revert = false;
959 if (header.id == R.id.account_add) {
960 revert = true;
961 }
962
963 super.onHeaderClick(header, position);
964
965 if (revert && mLastHeader != null) {
966 highlightHeader((int) mLastHeader.id);
967 } else {
968 mLastHeader = header;
969 }
970 }
971
972 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700973 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
974 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800975 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700976 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800977 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -0700978 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
979 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -0700980 if (UserManager.get(this).isLinkedUser()) {
981 titleRes = R.string.profile_info_settings_title;
982 } else {
983 titleRes = R.string.user_info_settings_title;
984 }
Amith Yamasania4379d62011-07-22 10:34:58 -0700985 }
Jean Chalard7dabe452012-05-10 18:08:07 +0900986 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
987 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -0700988 return true;
989 }
990
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400991 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -0700992 public boolean shouldUpRecreateTask(Intent targetIntent) {
993 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
994 }
995
Amith Yamasania4379d62011-07-22 10:34:58 -0700996 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700997 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700998 if (adapter == null) {
999 super.setListAdapter(null);
1000 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -04001001 DevicePolicyManager dpm =
1002 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
1003 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -07001004 }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001005 }
1006
Amith Yamasani56821db2012-06-05 13:20:45 -07001007 @Override
1008 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -07001009 // TODO: watch for package upgrades to invalidate cache; see 7206643
1010 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -07001011 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
1012 invalidateHeaders();
1013 }
1014
Amith Yamasani5203bdf2010-11-04 09:59:44 -07001015 /*
1016 * Settings subclasses for launching independently.
1017 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001018 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1019 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1020 public static class TetherSettingsActivity extends Settings { /* empty */ }
1021 public static class VpnSettingsActivity extends Settings { /* empty */ }
1022 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1023 public static class StorageSettingsActivity extends Settings { /* empty */ }
1024 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001025 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001026 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001027 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001028 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001029 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001030 public static class LocalePickerActivity extends Settings { /* empty */ }
1031 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1032 public static class SoundSettingsActivity extends Settings { /* empty */ }
1033 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1034 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1035 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1036 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Dianne Hackborna522a8e2013-01-15 19:02:05 -08001037 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001038 public static class StorageUseActivity extends Settings { /* empty */ }
1039 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1040 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001041 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001042 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001043 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001044 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001045 public static class RunningServicesActivity extends Settings { /* empty */ }
1046 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1047 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1048 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1049 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1050 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1051 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1052 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001053 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001054 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001055 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001056 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001057 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001058 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001059 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001060 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001061 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001062 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001063 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001064 public static class PrintSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001065}