blob: f01c03a7f66f931254c2219bdbe2c52db856852c [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) {
Amith Yamasani2972c012013-10-02 11:48:46 -0700519 if (!onIsHidingHeaders()) {
520 loadHeadersFromResource(R.xml.settings_headers, headers);
521 updateHeaderList(headers);
522 }
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700523 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700524
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700525 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700526 final boolean showDev = mDevelopmentPreferences.getBoolean(
527 DevelopmentSettings.PREF_SHOW,
528 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700529 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400530
531 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700532 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700533 while (i < target.size()) {
534 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700535 // Ids are integers, so downcasting
536 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400537 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700538 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700539 } else if (id == R.id.wifi_settings) {
540 // Remove WiFi Settings if WiFi service is not available.
541 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700542 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700543 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700544 } else if (id == R.id.bluetooth_settings) {
545 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700546 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700547 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700548 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700549 } else if (id == R.id.data_usage_settings) {
550 // Remove data usage when kernel module not enabled
551 final INetworkManagementService netManager = INetworkManagementService.Stub
552 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
553 try {
554 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700555 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700556 }
557 } catch (RemoteException e) {
558 // ignored
559 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900560 } else if (id == R.id.battery_settings) {
561 // Remove battery settings when battery is not available. (e.g. TV)
562
563 if (!mBatteryPresent) {
564 target.remove(i);
565 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700566 } else if (id == R.id.account_settings) {
567 int headerIndex = i + 1;
568 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700569 } else if (id == R.id.home_settings) {
Christopher Tate8243c9a2013-09-19 14:59:17 -0700570 if (!updateHomeSettingHeaders(header)) {
571 target.remove(i);
572 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700573 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700574 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700575 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700576 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700577 target.remove(i);
578 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700579 } else if (id == R.id.nfc_payment_settings) {
Martijn Coenen81ab8172013-09-30 12:07:02 -0700580 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
Martijn Coenen26515da2013-08-01 18:13:33 -0700581 target.remove(i);
Martijn Coenen81ab8172013-09-30 12:07:02 -0700582 } else {
583 // Only show if NFC is on and we have the HCE feature
584 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
585 if (!adapter.isEnabled() || !getPackageManager().hasSystemFeature(
586 PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
587 target.remove(i);
588 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700589 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700590 } else if (id == R.id.development_settings) {
591 if (!showDev) {
592 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700593 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400594 } else if (id == R.id.account_add) {
595 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
596 target.remove(i);
597 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700598 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700599
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900600 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700601 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700602 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700603 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700604 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700605
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700606 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900607 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800608 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700609 if (mFirstHeader == null &&
610 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
611 mFirstHeader = header;
612 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700613 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700614 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700615 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700616 }
617 }
618
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700619 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
620 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
621 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
622 for (String accountType : accountTypes) {
623 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700624 if (label == null) {
625 continue;
626 }
627
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700628 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
629 boolean skipToAccount = accounts.length == 1
630 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700631 Header accHeader = new Header();
632 accHeader.title = label;
633 if (accHeader.extras == null) {
634 accHeader.extras = new Bundle();
635 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700636 if (skipToAccount) {
637 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
638 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
639 accHeader.fragment = AccountSyncSettings.class.getName();
640 accHeader.fragmentArguments = new Bundle();
641 // Need this for the icon
642 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
643 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
644 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
645 accounts[0]);
646 } else {
647 accHeader.breadCrumbTitle = label;
648 accHeader.breadCrumbShortTitle = label;
649 accHeader.fragment = ManageAccountsSettings.class.getName();
650 accHeader.fragmentArguments = new Bundle();
651 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
652 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
653 accountType);
654 if (!isMultiPane()) {
655 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
656 label.toString());
657 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700658 }
659 accountHeaders.add(accHeader);
Amith Yamasani2972c012013-10-02 11:48:46 -0700660 mAuthenticatorHelper.preloadDrawableForType(this, accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700661 }
662
663 // Sort by label
664 Collections.sort(accountHeaders, new Comparator<Header>() {
665 @Override
666 public int compare(Header h1, Header h2) {
667 return h1.title.toString().compareTo(h2.title.toString());
668 }
669 });
670
671 for (Header header : accountHeaders) {
672 target.add(headerIndex++, header);
673 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700674 if (!mListeningToAccountUpdates) {
675 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
676 mListeningToAccountUpdates = true;
677 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700678 return headerIndex;
679 }
680
Christopher Tate8243c9a2013-09-19 14:59:17 -0700681 private boolean updateHomeSettingHeaders(Header header) {
Christopher Tatee238a472013-08-27 14:21:46 -0700682 try {
Jeff Sharkeyd572a032013-09-23 17:41:16 -0700683 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
684 getPackageManager().getHomeActivities(homeApps);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700685 if (homeApps.size() < 2) {
686 // When there's only one available home app, omit this settings
687 // category entirely at the top level UI.
688 return false;
689 }
Christopher Tatee238a472013-08-27 14:21:46 -0700690 } catch (Exception e) {
691 // Can't look up the home activity; bail on configuring the icon
692 Log.w(LOG_TAG, "Problem looking up home activity!", e);
693 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700694 return true;
Christopher Tatee238a472013-08-27 14:21:46 -0700695 }
696
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700697 private void getMetaData() {
698 try {
699 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
700 PackageManager.GET_META_DATA);
701 if (ai == null || ai.metaData == null) return;
702 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
703 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700704
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800705 // Check if it has a parent specified and create a Header object
706 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
707 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
708 if (parentFragmentClass != null) {
709 mParentHeader = new Header();
710 mParentHeader.fragment = parentFragmentClass;
711 if (parentHeaderTitleRes != 0) {
712 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
713 }
714 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700715 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700716 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700717 }
718 }
719
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800720 @Override
721 public boolean hasNextButton() {
722 return super.hasNextButton();
723 }
724
725 @Override
726 public Button getNextButton() {
727 return super.getNextButton();
728 }
729
Gilles Debunnee78c1872011-06-20 15:00:07 -0700730 private static class HeaderAdapter extends ArrayAdapter<Header> {
731 static final int HEADER_TYPE_CATEGORY = 0;
732 static final int HEADER_TYPE_NORMAL = 1;
733 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400734 static final int HEADER_TYPE_BUTTON = 3;
735 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700736
737 private final WifiEnabler mWifiEnabler;
738 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700739 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400740 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700741
742 private static class HeaderViewHolder {
743 ImageView icon;
744 TextView title;
745 TextView summary;
746 Switch switch_;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400747 ImageButton button_;
748 View divider_;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700749 }
750
751 private LayoutInflater mInflater;
752
753 static int getHeaderType(Header header) {
754 if (header.fragment == null && header.intent == null) {
755 return HEADER_TYPE_CATEGORY;
756 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
757 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400758 } else if (header.id == R.id.security_settings) {
759 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700760 } else {
761 return HEADER_TYPE_NORMAL;
762 }
763 }
764
765 @Override
766 public int getItemViewType(int position) {
767 Header header = getItem(position);
768 return getHeaderType(header);
769 }
770
771 @Override
772 public boolean areAllItemsEnabled() {
773 return false; // because of categories
774 }
775
776 @Override
777 public boolean isEnabled(int position) {
778 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
779 }
780
781 @Override
782 public int getViewTypeCount() {
783 return HEADER_TYPE_COUNT;
784 }
785
786 @Override
787 public boolean hasStableIds() {
788 return true;
789 }
790
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700791 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400792 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700793 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700794
795 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700796 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700797
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700798 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700799 // Switches inflated from their layouts. Must be done before adapter is set in super
800 mWifiEnabler = new WifiEnabler(context, new Switch(context));
801 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400802 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700803 }
804
805 @Override
806 public View getView(int position, View convertView, ViewGroup parent) {
807 HeaderViewHolder holder;
808 Header header = getItem(position);
809 int headerType = getHeaderType(header);
810 View view = null;
811
812 if (convertView == null) {
813 holder = new HeaderViewHolder();
814 switch (headerType) {
815 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700816 view = new TextView(getContext(), null,
817 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700818 holder.title = (TextView) view;
819 break;
820
821 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700822 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
823 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700824 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700825 holder.title = (TextView)
826 view.findViewById(com.android.internal.R.id.title);
827 holder.summary = (TextView)
828 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700829 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
830 break;
831
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400832 case HEADER_TYPE_BUTTON:
833 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
834 false);
835 holder.icon = (ImageView) view.findViewById(R.id.icon);
836 holder.title = (TextView)
837 view.findViewById(com.android.internal.R.id.title);
838 holder.summary = (TextView)
839 view.findViewById(com.android.internal.R.id.summary);
840 holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget);
841 holder.divider_ = view.findViewById(R.id.divider);
842 break;
843
Gilles Debunnee78c1872011-06-20 15:00:07 -0700844 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700845 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700846 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700847 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700848 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700849 holder.title = (TextView)
850 view.findViewById(com.android.internal.R.id.title);
851 holder.summary = (TextView)
852 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700853 break;
854 }
855 view.setTag(holder);
856 } else {
857 view = convertView;
858 holder = (HeaderViewHolder) view.getTag();
859 }
860
861 // All view fields must be updated every time, because the view may be recycled
862 switch (headerType) {
863 case HEADER_TYPE_CATEGORY:
864 holder.title.setText(header.getTitle(getContext().getResources()));
865 break;
866
867 case HEADER_TYPE_SWITCH:
868 // Would need a different treatment if the main menu had more switches
869 if (header.id == R.id.wifi_settings) {
870 mWifiEnabler.setSwitch(holder.switch_);
871 } else {
872 mBluetoothEnabler.setSwitch(holder.switch_);
873 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400874 updateCommonHeaderView(header, holder);
875 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700876
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400877 case HEADER_TYPE_BUTTON:
878 if (header.id == R.id.security_settings) {
879 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
880 if (hasCert) {
881 holder.button_.setVisibility(View.VISIBLE);
882 holder.divider_.setVisibility(View.VISIBLE);
883 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
884 if (isManaged) {
885 holder.button_.setImageResource(R.drawable.ic_qs_certificate_info);
886 } else {
887 holder.button_.setImageResource(
888 android.R.drawable.stat_notify_error);
889 }
890 holder.button_.setOnClickListener(new OnClickListener() {
891 @Override
892 public void onClick(View v) {
893 Intent intent = new Intent(
894 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
895 getContext().startActivity(intent);
896 }
897 });
898 } else {
899 holder.button_.setVisibility(View.GONE);
900 holder.divider_.setVisibility(View.GONE);
901 }
902 }
903 updateCommonHeaderView(header, holder);
904 break;
905
Gilles Debunnee78c1872011-06-20 15:00:07 -0700906 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400907 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700908 break;
909 }
910
911 return view;
912 }
913
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400914 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
915 if (header.extras != null
916 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
917 String accType = header.extras.getString(
918 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
919 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
920 setHeaderIcon(holder, icon);
921 } else if (header.extras != null &&
922 header.extras.containsKey(HomeSettings.CURRENT_HOME)) {
923 ActivityInfo ai = header.extras.getParcelable(HomeSettings.CURRENT_HOME);
924 Drawable icon = ai.loadIcon(getContext().getPackageManager());
925 setHeaderIcon(holder, icon);
926 } else {
927 holder.icon.setImageResource(header.iconRes);
928 }
929 holder.title.setText(header.getTitle(getContext().getResources()));
930 CharSequence summary = header.getSummary(getContext().getResources());
931 if (!TextUtils.isEmpty(summary)) {
932 holder.summary.setVisibility(View.VISIBLE);
933 holder.summary.setText(summary);
934 } else {
935 holder.summary.setVisibility(View.GONE);
936 }
937 }
938
Christopher Tatee238a472013-08-27 14:21:46 -0700939 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
940 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
941 lp.width = getContext().getResources().getDimensionPixelSize(
942 R.dimen.header_icon_width);
943 lp.height = lp.width;
944 holder.icon.setLayoutParams(lp);
945 holder.icon.setImageDrawable(icon);
946 }
947
Gilles Debunnee78c1872011-06-20 15:00:07 -0700948 public void resume() {
949 mWifiEnabler.resume();
950 mBluetoothEnabler.resume();
951 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700952
Gilles Debunnee78c1872011-06-20 15:00:07 -0700953 public void pause() {
954 mWifiEnabler.pause();
955 mBluetoothEnabler.pause();
956 }
957 }
958
959 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700960 public void onHeaderClick(Header header, int position) {
961 boolean revert = false;
962 if (header.id == R.id.account_add) {
963 revert = true;
964 }
965
966 super.onHeaderClick(header, position);
967
968 if (revert && mLastHeader != null) {
969 highlightHeader((int) mLastHeader.id);
970 } else {
971 mLastHeader = header;
972 }
973 }
974
975 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700976 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
977 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800978 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700979 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800980 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -0700981 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
982 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -0700983 if (UserManager.get(this).isLinkedUser()) {
984 titleRes = R.string.profile_info_settings_title;
985 } else {
986 titleRes = R.string.user_info_settings_title;
987 }
Amith Yamasania4379d62011-07-22 10:34:58 -0700988 }
Jean Chalard7dabe452012-05-10 18:08:07 +0900989 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
990 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -0700991 return true;
992 }
993
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400994 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -0700995 public boolean shouldUpRecreateTask(Intent targetIntent) {
996 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
997 }
998
Amith Yamasania4379d62011-07-22 10:34:58 -0700999 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -07001000 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -07001001 if (adapter == null) {
1002 super.setListAdapter(null);
1003 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -04001004 DevicePolicyManager dpm =
1005 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
1006 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -07001007 }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001008 }
1009
Amith Yamasani56821db2012-06-05 13:20:45 -07001010 @Override
1011 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -07001012 // TODO: watch for package upgrades to invalidate cache; see 7206643
1013 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -07001014 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
1015 invalidateHeaders();
1016 }
1017
Amith Yamasani5203bdf2010-11-04 09:59:44 -07001018 /*
1019 * Settings subclasses for launching independently.
1020 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001021 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1022 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1023 public static class TetherSettingsActivity extends Settings { /* empty */ }
1024 public static class VpnSettingsActivity extends Settings { /* empty */ }
1025 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1026 public static class StorageSettingsActivity extends Settings { /* empty */ }
1027 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001028 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001029 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001030 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001031 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001032 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001033 public static class LocalePickerActivity extends Settings { /* empty */ }
1034 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1035 public static class SoundSettingsActivity extends Settings { /* empty */ }
1036 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1037 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1038 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1039 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Dianne Hackborna522a8e2013-01-15 19:02:05 -08001040 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001041 public static class StorageUseActivity extends Settings { /* empty */ }
1042 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1043 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001044 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001045 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001046 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001047 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001048 public static class RunningServicesActivity extends Settings { /* empty */ }
1049 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1050 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1051 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1052 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1053 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1054 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1055 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001056 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001057 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001058 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001059 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001060 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001061 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001062 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001063 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001064 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001065 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001066 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001067 public static class PrintSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001068}