blob: ac67a38af5c4e8f960094546e5dd891a1f347589 [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;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070035import android.os.Bundle;
Jeff Sharkey34e964d2012-04-21 15:41:48 -070036import android.os.INetworkManagementService;
37import android.os.RemoteException;
38import android.os.ServiceManager;
Dianne Hackbornbb06a422012-08-16 11:01:57 -070039import android.os.UserHandle;
Jeff Sharkey44202462012-09-19 13:13:45 -070040import android.os.UserManager;
Amith Yamasania4379d62011-07-22 10:34:58 -070041import android.preference.Preference;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070042import android.preference.PreferenceActivity;
Amith Yamasania4379d62011-07-22 10:34:58 -070043import android.preference.PreferenceFragment;
Gilles Debunnee78c1872011-06-20 15:00:07 -070044import android.text.TextUtils;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080045import android.util.Log;
Gilles Debunnee78c1872011-06-20 15:00:07 -070046import android.view.LayoutInflater;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080047import android.view.View;
48import android.view.View.OnClickListener;
Gilles Debunnee78c1872011-06-20 15:00:07 -070049import android.view.ViewGroup;
50import android.widget.ArrayAdapter;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080051import android.widget.Button;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -040052import android.widget.ImageButton;
Gilles Debunnee78c1872011-06-20 15:00:07 -070053import android.widget.ImageView;
54import android.widget.ListAdapter;
55import android.widget.Switch;
56import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080057
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080058import com.android.internal.util.ArrayUtils;
Amith Yamasania677ee22013-07-26 13:38:41 -070059import com.android.settings.accessibility.AccessibilitySettings;
Alan Viverette341ff662013-07-18 17:49:33 -070060import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
Alan Viverette9b625f02013-09-11 13:03:14 -070061import com.android.settings.accessibility.ToggleCaptioningPreferenceFragment;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080062import com.android.settings.accounts.AccountSyncSettings;
63import com.android.settings.accounts.AuthenticatorHelper;
64import com.android.settings.accounts.ManageAccountsSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070065import com.android.settings.applications.AppOpsSummary;
66import com.android.settings.applications.ManageApplications;
Dianne Hackbornc6d658e2013-08-08 12:57:53 -070067import com.android.settings.applications.ProcessStatsUi;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080068import com.android.settings.bluetooth.BluetoothEnabler;
69import com.android.settings.bluetooth.BluetoothSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070070import com.android.settings.deviceinfo.Memory;
71import com.android.settings.deviceinfo.UsbSettings;
72import com.android.settings.fuelgauge.PowerUsageSummary;
73import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
Amith Yamasani3a14ae22013-08-30 15:43:44 -070074import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070075import com.android.settings.inputmethod.SpellCheckersSettings;
76import com.android.settings.inputmethod.UserDictionaryList;
Amith Yamasanie9904202013-08-01 10:26:14 -070077import com.android.settings.location.LocationSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070078import com.android.settings.nfc.AndroidBeam;
Martijn Coenen53083ab2013-08-09 13:37:38 -070079import com.android.settings.nfc.PaymentSettings;
Svetoslav2d531652013-09-03 21:32:40 -070080import com.android.settings.print.PrintServiceSettingsFragment;
81import com.android.settings.print.PrintSettingsFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070082import com.android.settings.tts.TextToSpeechSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070083import com.android.settings.users.UserSettings;
84import com.android.settings.vpn2.VpnSettings;
Jeff Sharkey0c3634c2013-02-20 12:35:16 -080085import com.android.settings.wfd.WifiDisplaySettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070086import com.android.settings.wifi.AdvancedWifiSettings;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080087import com.android.settings.wifi.WifiEnabler;
88import com.android.settings.wifi.WifiSettings;
89import com.android.settings.wifi.p2p.WifiP2pSettings;
90
Gilles Debunnee78c1872011-06-20 15:00:07 -070091import java.util.ArrayList;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070092import java.util.Collections;
93import java.util.Comparator;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070094import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070095import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -070096
97/**
98 * Top-level settings activity to handle single pane and double pane UI layout.
99 */
Amith Yamasani56821db2012-06-05 13:20:45 -0700100public class Settings extends PreferenceActivity
101 implements ButtonBarHandler, OnAccountsUpdateListener {
Amith Yamasanid7993472010-08-18 13:59:28 -0700102
Gilles Debunnee78c1872011-06-20 15:00:07 -0700103 private static final String LOG_TAG = "Settings";
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700104
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700105 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700106 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700107 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700108 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800109 private static final String META_DATA_KEY_PARENT_TITLE =
110 "com.android.settings.PARENT_FRAGMENT_TITLE";
111 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
112 "com.android.settings.PARENT_FRAGMENT_CLASS";
113
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800114 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700115
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800116 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
117 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700118
119 private String mFragmentClass;
120 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -0800121 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800122 private Header mCurrentHeader;
123 private Header mParentHeader;
124 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700125
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700126 // Show only these settings for restricted users
127 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700128 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700129 R.id.wifi_settings,
130 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700131 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700132 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700133 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700134 R.id.sound_settings,
135 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700136 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700137 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700138 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700139 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700140 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700141 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700142 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700143 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700144 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700145 R.id.account_add,
146 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700147 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700148 R.id.about_settings,
Svetoslav Ganovd4c7b492013-06-11 21:15:11 -0700149 R.id.accessibility_settings,
Martijn Coenen26515da2013-08-01 18:13:33 -0700150 R.id.print_settings,
Christopher Tatee238a472013-08-27 14:21:46 -0700151 R.id.nfc_payment_settings,
152 R.id.home_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700153 };
154
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700155 private SharedPreferences mDevelopmentPreferences;
156 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
157
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700158 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700159
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700160 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
161
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700162 private AuthenticatorHelper mAuthenticatorHelper;
163 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700164 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700165
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900166 private boolean mBatteryPresent = true;
167 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
168
169 @Override
170 public void onReceive(Context context, Intent intent) {
171 String action = intent.getAction();
172 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
173 boolean batteryPresent = Utils.isBatteryPresent(intent);
174
175 if (mBatteryPresent != batteryPresent) {
176 mBatteryPresent = batteryPresent;
177 invalidateHeaders();
178 }
179 }
180 }
181 };
182
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700183 @Override
184 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800185 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
186 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700187 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700188
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700189 mAuthenticatorHelper = new AuthenticatorHelper();
190 mAuthenticatorHelper.updateAuthDescriptions(this);
191 mAuthenticatorHelper.onAccountsUpdated(this, null);
192
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700193 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
194 Context.MODE_PRIVATE);
195
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700196 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800197 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700198 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800199 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700200
Gilles Debunne3661b622011-06-27 11:19:16 -0700201 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700202 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800203 // Force the title so that it doesn't get overridden by a direct launch of
204 // a specific settings screen.
205 setTitle(R.string.settings_label);
206 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800207
208 // Retrieve any saved state
209 if (savedInstanceState != null) {
210 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
211 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
212 }
213
214 // If the current header was saved, switch to it
215 if (savedInstanceState != null && mCurrentHeader != null) {
216 //switchToHeaderLocal(mCurrentHeader);
217 showBreadCrumbs(mCurrentHeader.title, null);
218 }
219
220 if (mParentHeader != null) {
221 setParentTitle(mParentHeader.title, null, new OnClickListener() {
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400222 @Override
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800223 public void onClick(View v) {
224 switchToParent(mParentHeader.fragment);
225 }
226 });
227 }
Gilles Debunnedc7101f2011-06-27 12:00:49 -0700228
Amith Yamasani3d384f42012-05-11 15:22:04 -0700229 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
230 if (onIsMultiPane()) {
231 getActionBar().setDisplayHomeAsUpEnabled(false);
232 getActionBar().setHomeButtonEnabled(false);
233 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800234 }
235
236 @Override
237 protected void onSaveInstanceState(Bundle outState) {
238 super.onSaveInstanceState(outState);
239
240 // Save the current fragment, if it is the same as originally launched
241 if (mCurrentHeader != null) {
242 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
243 }
244 if (mParentHeader != null) {
245 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
246 }
247 }
248
Gilles Debunnee78c1872011-06-20 15:00:07 -0700249 @Override
250 public void onResume() {
251 super.onResume();
252
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700253 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
254 @Override
255 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
256 invalidateHeaders();
257 }
258 };
259 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
260 mDevelopmentPreferencesListener);
261
Gilles Debunnee78c1872011-06-20 15:00:07 -0700262 ListAdapter listAdapter = getListAdapter();
263 if (listAdapter instanceof HeaderAdapter) {
264 ((HeaderAdapter) listAdapter).resume();
265 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700266 invalidateHeaders();
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900267
268 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700269 }
270
271 @Override
272 public void onPause() {
273 super.onPause();
274
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900275 unregisterReceiver(mBatteryInfoReceiver);
276
Gilles Debunnee78c1872011-06-20 15:00:07 -0700277 ListAdapter listAdapter = getListAdapter();
278 if (listAdapter instanceof HeaderAdapter) {
279 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700280 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700281
282 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
283 mDevelopmentPreferencesListener);
284 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700285 }
286
287 @Override
288 public void onDestroy() {
289 super.onDestroy();
290 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700291 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700292 }
293 }
294
Amith Yamasani56f51a82013-08-05 10:07:23 -0700295 @Override
296 public boolean onIsMultiPane() {
297 return false;
298 }
299
Amith Yamasania677ee22013-07-26 13:38:41 -0700300 private static final String[] ENTRY_FRAGMENTS = {
301 WirelessSettings.class.getName(),
302 WifiSettings.class.getName(),
303 AdvancedWifiSettings.class.getName(),
304 BluetoothSettings.class.getName(),
305 TetherSettings.class.getName(),
306 WifiP2pSettings.class.getName(),
307 VpnSettings.class.getName(),
308 DateTimeSettings.class.getName(),
309 LocalePicker.class.getName(),
310 InputMethodAndLanguageSettings.class.getName(),
311 SpellCheckersSettings.class.getName(),
312 UserDictionaryList.class.getName(),
313 UserDictionarySettings.class.getName(),
314 SoundSettings.class.getName(),
315 DisplaySettings.class.getName(),
316 DeviceInfoSettings.class.getName(),
317 ManageApplications.class.getName(),
Dianne Hackbornc6d658e2013-08-08 12:57:53 -0700318 ProcessStatsUi.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700319 NotificationStation.class.getName(),
320 AppOpsSummary.class.getName(),
321 LocationSettings.class.getName(),
322 SecuritySettings.class.getName(),
323 PrivacySettings.class.getName(),
324 DeviceAdminSettings.class.getName(),
325 AccessibilitySettings.class.getName(),
Alan Viverette9b625f02013-09-11 13:03:14 -0700326 ToggleCaptioningPreferenceFragment.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700327 TextToSpeechSettings.class.getName(),
328 Memory.class.getName(),
329 DevelopmentSettings.class.getName(),
330 UsbSettings.class.getName(),
331 AndroidBeam.class.getName(),
332 WifiDisplaySettings.class.getName(),
333 PowerUsageSummary.class.getName(),
334 AccountSyncSettings.class.getName(),
335 CryptKeeperSettings.class.getName(),
336 DataUsageSummary.class.getName(),
337 DreamSettings.class.getName(),
338 UserSettings.class.getName(),
339 NotificationAccessSettings.class.getName(),
Amith Yamasaniee226f92013-08-05 11:02:16 -0700340 ManageAccountsSettings.class.getName(),
Svetoslav2d531652013-09-03 21:32:40 -0700341 PrintSettingsFragment.class.getName(),
Martijn Coenen53083ab2013-08-09 13:37:38 -0700342 TrustedCredentialsSettings.class.getName(),
Amith Yamasani3a14ae22013-08-30 15:43:44 -0700343 PaymentSettings.class.getName(),
344 KeyboardLayoutPickerFragment.class.getName()
Amith Yamasania677ee22013-07-26 13:38:41 -0700345 };
346
347 @Override
348 protected boolean isValidFragment(String fragmentName) {
349 // Almost all fragments are wrapped in this,
350 // except for a few that have their own activities.
351 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
352 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
353 }
354 return false;
355 }
356
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800357 private void switchToHeaderLocal(Header header) {
358 mInLocalHeaderSwitch = true;
359 switchToHeader(header);
360 mInLocalHeaderSwitch = false;
361 }
362
363 @Override
364 public void switchToHeader(Header header) {
365 if (!mInLocalHeaderSwitch) {
366 mCurrentHeader = null;
367 mParentHeader = null;
368 }
369 super.switchToHeader(header);
370 }
371
372 /**
373 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800374 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800375 */
376 private void switchToParent(String className) {
377 final ComponentName cn = new ComponentName(this, className);
378 try {
379 final PackageManager pm = getPackageManager();
380 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
381
382 if (parentInfo != null && parentInfo.metaData != null) {
383 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
384 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
385 Header parentHeader = new Header();
386 parentHeader.fragment = fragmentClass;
387 parentHeader.title = fragmentTitle;
388 mCurrentHeader = parentHeader;
389
390 switchToHeaderLocal(parentHeader);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700391 highlightHeader(mTopLevelHeaderId);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800392
393 mParentHeader = new Header();
394 mParentHeader.fragment
395 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
396 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
397 }
398 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700399 Log.w(LOG_TAG, "Could not find parent activity : " + className);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800400 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700401 }
402
Amith Yamasani3965ae62010-11-15 14:45:19 -0800403 @Override
404 public void onNewIntent(Intent intent) {
405 super.onNewIntent(intent);
406
407 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700408 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
409 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
410 switchToHeaderLocal(mFirstHeader);
411 }
412 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800413 }
414 }
415
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700416 private void highlightHeader(int id) {
417 if (id != 0) {
418 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700419 if (index != null) {
420 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700421 if (isMultiPane()) {
422 getListView().smoothScrollToPosition(index);
423 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700424 }
425 }
426 }
427
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700428 @Override
429 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700430 Intent superIntent = super.getIntent();
431 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700432 // This is called from super.onCreate, isMultiPane() is not yet reliable
433 // Do not use onIsHidingHeaders either, which relies itself on this method
434 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700435 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700436 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700437 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700438 if (args != null) {
439 args = new Bundle(args);
440 } else {
441 args = new Bundle();
442 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700443 args.putParcelable("intent", superIntent);
444 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700445 return modIntent;
446 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700447 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700448 }
449
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700450 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700451 * Checks if the component name in the intent is different from the Settings class and
452 * returns the class name to load as a fragment.
453 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700454 protected String getStartingFragmentClass(Intent intent) {
455 if (mFragmentClass != null) return mFragmentClass;
456
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700457 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700458 if (intentClass.equals(getClass().getName())) return null;
459
Dianne Hackbornee293792010-11-01 12:32:33 -0700460 if ("com.android.settings.ManageApplications".equals(intentClass)
461 || "com.android.settings.RunningServices".equals(intentClass)
462 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700463 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700464 intentClass = com.android.settings.applications.ManageApplications.class.getName();
465 }
466
Amith Yamasani379d9b02010-09-27 12:03:59 -0700467 return intentClass;
468 }
469
470 /**
471 * Override initial header when an activity-alias is causing Settings to be launched
472 * for a specific fragment encoded in the android:name parameter.
473 */
474 @Override
475 public Header onGetInitialHeader() {
476 String fragmentClass = getStartingFragmentClass(super.getIntent());
477 if (fragmentClass != null) {
478 Header header = new Header();
479 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800480 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700481 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800482 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700483 return header;
484 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700485
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700486 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700487 }
488
Dianne Hackbornb7258182011-03-15 16:23:55 -0700489 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700490 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
491 int titleRes, int shortTitleRes) {
492 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
493 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700494
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800495 // Some fragments want split ActionBar; these should stay in sync with
496 // uiOptions for fragments also defined as activities in manifest.
497 if (WifiSettings.class.getName().equals(fragmentName) ||
498 WifiP2pSettings.class.getName().equals(fragmentName) ||
Jeff Sharkey0c3634c2013-02-20 12:35:16 -0800499 WifiDisplaySettings.class.getName().equals(fragmentName) ||
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800500 BluetoothSettings.class.getName().equals(fragmentName) ||
501 DreamSettings.class.getName().equals(fragmentName) ||
Lifu Tangd5fbbc42013-08-01 17:23:10 -0700502 LocationSettings.class.getName().equals(fragmentName) ||
Svetoslav2d531652013-09-03 21:32:40 -0700503 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
504 PrintSettingsFragment.class.getName().equals(fragmentName) ||
505 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800506 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700507 }
508
Dianne Hackbornb7258182011-03-15 16:23:55 -0700509 intent.setClass(this, SubSettings.class);
510 return intent;
511 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700512
Amith Yamasani379d9b02010-09-27 12:03:59 -0700513 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700514 * Populate the activity with the top-level headers.
515 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700516 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700517 public void onBuildHeaders(List<Header> headers) {
518 loadHeadersFromResource(R.xml.settings_headers, headers);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700519 updateHeaderList(headers);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700520 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700521
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700522 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700523 final boolean showDev = mDevelopmentPreferences.getBoolean(
524 DevelopmentSettings.PREF_SHOW,
525 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700526 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400527
528 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700529 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700530 while (i < target.size()) {
531 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700532 // Ids are integers, so downcasting
533 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400534 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700535 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700536 } else if (id == R.id.wifi_settings) {
537 // Remove WiFi Settings if WiFi service is not available.
538 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700539 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700540 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700541 } else if (id == R.id.bluetooth_settings) {
542 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700543 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700544 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700545 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700546 } else if (id == R.id.data_usage_settings) {
547 // Remove data usage when kernel module not enabled
548 final INetworkManagementService netManager = INetworkManagementService.Stub
549 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
550 try {
551 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700552 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700553 }
554 } catch (RemoteException e) {
555 // ignored
556 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900557 } else if (id == R.id.battery_settings) {
558 // Remove battery settings when battery is not available. (e.g. TV)
559
560 if (!mBatteryPresent) {
561 target.remove(i);
562 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700563 } else if (id == R.id.account_settings) {
564 int headerIndex = i + 1;
565 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700566 } else if (id == R.id.home_settings) {
Christopher Tate8243c9a2013-09-19 14:59:17 -0700567 if (!updateHomeSettingHeaders(header)) {
568 target.remove(i);
569 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700570 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700571 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700572 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700573 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700574 target.remove(i);
575 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700576 } else if (id == R.id.nfc_payment_settings) {
577 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HCE)) {
578 target.remove(i);
579 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700580 } else if (id == R.id.development_settings) {
581 if (!showDev) {
582 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700583 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400584 } else if (id == R.id.account_add) {
585 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
586 target.remove(i);
587 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700588 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700589
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900590 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700591 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700592 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700593 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700594 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700595
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700596 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900597 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800598 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700599 if (mFirstHeader == null &&
600 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
601 mFirstHeader = header;
602 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700603 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700604 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700605 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700606 }
607 }
608
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700609 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
610 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
611 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
612 for (String accountType : accountTypes) {
613 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700614 if (label == null) {
615 continue;
616 }
617
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700618 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
619 boolean skipToAccount = accounts.length == 1
620 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700621 Header accHeader = new Header();
622 accHeader.title = label;
623 if (accHeader.extras == null) {
624 accHeader.extras = new Bundle();
625 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700626 if (skipToAccount) {
627 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
628 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
629 accHeader.fragment = AccountSyncSettings.class.getName();
630 accHeader.fragmentArguments = new Bundle();
631 // Need this for the icon
632 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
633 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
634 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
635 accounts[0]);
636 } else {
637 accHeader.breadCrumbTitle = label;
638 accHeader.breadCrumbShortTitle = label;
639 accHeader.fragment = ManageAccountsSettings.class.getName();
640 accHeader.fragmentArguments = new Bundle();
641 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
642 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
643 accountType);
644 if (!isMultiPane()) {
645 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
646 label.toString());
647 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700648 }
649 accountHeaders.add(accHeader);
650 }
651
652 // Sort by label
653 Collections.sort(accountHeaders, new Comparator<Header>() {
654 @Override
655 public int compare(Header h1, Header h2) {
656 return h1.title.toString().compareTo(h2.title.toString());
657 }
658 });
659
660 for (Header header : accountHeaders) {
661 target.add(headerIndex++, header);
662 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700663 if (!mListeningToAccountUpdates) {
664 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
665 mListeningToAccountUpdates = true;
666 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700667 return headerIndex;
668 }
669
Christopher Tate8243c9a2013-09-19 14:59:17 -0700670 private boolean updateHomeSettingHeaders(Header header) {
Christopher Tatee238a472013-08-27 14:21:46 -0700671 try {
Jeff Sharkeyd572a032013-09-23 17:41:16 -0700672 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
673 getPackageManager().getHomeActivities(homeApps);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700674 if (homeApps.size() < 2) {
675 // When there's only one available home app, omit this settings
676 // category entirely at the top level UI.
677 return false;
678 }
Christopher Tatee238a472013-08-27 14:21:46 -0700679 } catch (Exception e) {
680 // Can't look up the home activity; bail on configuring the icon
681 Log.w(LOG_TAG, "Problem looking up home activity!", e);
682 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700683 return true;
Christopher Tatee238a472013-08-27 14:21:46 -0700684 }
685
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700686 private void getMetaData() {
687 try {
688 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
689 PackageManager.GET_META_DATA);
690 if (ai == null || ai.metaData == null) return;
691 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
692 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700693
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800694 // Check if it has a parent specified and create a Header object
695 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
696 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
697 if (parentFragmentClass != null) {
698 mParentHeader = new Header();
699 mParentHeader.fragment = parentFragmentClass;
700 if (parentHeaderTitleRes != 0) {
701 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
702 }
703 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700704 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700705 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700706 }
707 }
708
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800709 @Override
710 public boolean hasNextButton() {
711 return super.hasNextButton();
712 }
713
714 @Override
715 public Button getNextButton() {
716 return super.getNextButton();
717 }
718
Gilles Debunnee78c1872011-06-20 15:00:07 -0700719 private static class HeaderAdapter extends ArrayAdapter<Header> {
720 static final int HEADER_TYPE_CATEGORY = 0;
721 static final int HEADER_TYPE_NORMAL = 1;
722 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400723 static final int HEADER_TYPE_BUTTON = 3;
724 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700725
726 private final WifiEnabler mWifiEnabler;
727 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700728 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400729 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700730
731 private static class HeaderViewHolder {
732 ImageView icon;
733 TextView title;
734 TextView summary;
735 Switch switch_;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400736 ImageButton button_;
737 View divider_;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700738 }
739
740 private LayoutInflater mInflater;
741
742 static int getHeaderType(Header header) {
743 if (header.fragment == null && header.intent == null) {
744 return HEADER_TYPE_CATEGORY;
745 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
746 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400747 } else if (header.id == R.id.security_settings) {
748 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700749 } else {
750 return HEADER_TYPE_NORMAL;
751 }
752 }
753
754 @Override
755 public int getItemViewType(int position) {
756 Header header = getItem(position);
757 return getHeaderType(header);
758 }
759
760 @Override
761 public boolean areAllItemsEnabled() {
762 return false; // because of categories
763 }
764
765 @Override
766 public boolean isEnabled(int position) {
767 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
768 }
769
770 @Override
771 public int getViewTypeCount() {
772 return HEADER_TYPE_COUNT;
773 }
774
775 @Override
776 public boolean hasStableIds() {
777 return true;
778 }
779
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700780 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400781 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700782 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700783
784 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700785 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700786
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700787 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700788 // Switches inflated from their layouts. Must be done before adapter is set in super
789 mWifiEnabler = new WifiEnabler(context, new Switch(context));
790 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400791 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700792 }
793
794 @Override
795 public View getView(int position, View convertView, ViewGroup parent) {
796 HeaderViewHolder holder;
797 Header header = getItem(position);
798 int headerType = getHeaderType(header);
799 View view = null;
800
801 if (convertView == null) {
802 holder = new HeaderViewHolder();
803 switch (headerType) {
804 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700805 view = new TextView(getContext(), null,
806 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700807 holder.title = (TextView) view;
808 break;
809
810 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700811 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
812 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700813 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700814 holder.title = (TextView)
815 view.findViewById(com.android.internal.R.id.title);
816 holder.summary = (TextView)
817 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700818 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
819 break;
820
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400821 case HEADER_TYPE_BUTTON:
822 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
823 false);
824 holder.icon = (ImageView) view.findViewById(R.id.icon);
825 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);
829 holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget);
830 holder.divider_ = view.findViewById(R.id.divider);
831 break;
832
Gilles Debunnee78c1872011-06-20 15:00:07 -0700833 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700834 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700835 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700836 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700837 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700838 holder.title = (TextView)
839 view.findViewById(com.android.internal.R.id.title);
840 holder.summary = (TextView)
841 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700842 break;
843 }
844 view.setTag(holder);
845 } else {
846 view = convertView;
847 holder = (HeaderViewHolder) view.getTag();
848 }
849
850 // All view fields must be updated every time, because the view may be recycled
851 switch (headerType) {
852 case HEADER_TYPE_CATEGORY:
853 holder.title.setText(header.getTitle(getContext().getResources()));
854 break;
855
856 case HEADER_TYPE_SWITCH:
857 // Would need a different treatment if the main menu had more switches
858 if (header.id == R.id.wifi_settings) {
859 mWifiEnabler.setSwitch(holder.switch_);
860 } else {
861 mBluetoothEnabler.setSwitch(holder.switch_);
862 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400863 updateCommonHeaderView(header, holder);
864 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700865
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400866 case HEADER_TYPE_BUTTON:
867 if (header.id == R.id.security_settings) {
868 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
869 if (hasCert) {
870 holder.button_.setVisibility(View.VISIBLE);
871 holder.divider_.setVisibility(View.VISIBLE);
872 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
873 if (isManaged) {
874 holder.button_.setImageResource(R.drawable.ic_qs_certificate_info);
875 } else {
876 holder.button_.setImageResource(
877 android.R.drawable.stat_notify_error);
878 }
879 holder.button_.setOnClickListener(new OnClickListener() {
880 @Override
881 public void onClick(View v) {
882 Intent intent = new Intent(
883 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
884 getContext().startActivity(intent);
885 }
886 });
887 } else {
888 holder.button_.setVisibility(View.GONE);
889 holder.divider_.setVisibility(View.GONE);
890 }
891 }
892 updateCommonHeaderView(header, holder);
893 break;
894
Gilles Debunnee78c1872011-06-20 15:00:07 -0700895 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400896 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700897 break;
898 }
899
900 return view;
901 }
902
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400903 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
904 if (header.extras != null
905 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
906 String accType = header.extras.getString(
907 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
908 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
909 setHeaderIcon(holder, icon);
910 } else if (header.extras != null &&
911 header.extras.containsKey(HomeSettings.CURRENT_HOME)) {
912 ActivityInfo ai = header.extras.getParcelable(HomeSettings.CURRENT_HOME);
913 Drawable icon = ai.loadIcon(getContext().getPackageManager());
914 setHeaderIcon(holder, icon);
915 } else {
916 holder.icon.setImageResource(header.iconRes);
917 }
918 holder.title.setText(header.getTitle(getContext().getResources()));
919 CharSequence summary = header.getSummary(getContext().getResources());
920 if (!TextUtils.isEmpty(summary)) {
921 holder.summary.setVisibility(View.VISIBLE);
922 holder.summary.setText(summary);
923 } else {
924 holder.summary.setVisibility(View.GONE);
925 }
926 }
927
Christopher Tatee238a472013-08-27 14:21:46 -0700928 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
929 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
930 lp.width = getContext().getResources().getDimensionPixelSize(
931 R.dimen.header_icon_width);
932 lp.height = lp.width;
933 holder.icon.setLayoutParams(lp);
934 holder.icon.setImageDrawable(icon);
935 }
936
Gilles Debunnee78c1872011-06-20 15:00:07 -0700937 public void resume() {
938 mWifiEnabler.resume();
939 mBluetoothEnabler.resume();
940 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700941
Gilles Debunnee78c1872011-06-20 15:00:07 -0700942 public void pause() {
943 mWifiEnabler.pause();
944 mBluetoothEnabler.pause();
945 }
946 }
947
948 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700949 public void onHeaderClick(Header header, int position) {
950 boolean revert = false;
951 if (header.id == R.id.account_add) {
952 revert = true;
953 }
954
955 super.onHeaderClick(header, position);
956
957 if (revert && mLastHeader != null) {
958 highlightHeader((int) mLastHeader.id);
959 } else {
960 mLastHeader = header;
961 }
962 }
963
964 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700965 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
966 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800967 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700968 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800969 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -0700970 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
971 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -0700972 if (UserManager.get(this).isLinkedUser()) {
973 titleRes = R.string.profile_info_settings_title;
974 } else {
975 titleRes = R.string.user_info_settings_title;
976 }
Amith Yamasania4379d62011-07-22 10:34:58 -0700977 }
Jean Chalard7dabe452012-05-10 18:08:07 +0900978 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
979 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -0700980 return true;
981 }
982
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400983 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -0700984 public boolean shouldUpRecreateTask(Intent targetIntent) {
985 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
986 }
987
Amith Yamasania4379d62011-07-22 10:34:58 -0700988 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700989 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700990 if (adapter == null) {
991 super.setListAdapter(null);
992 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400993 DevicePolicyManager dpm =
994 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
995 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700996 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700997 }
998
Amith Yamasani56821db2012-06-05 13:20:45 -0700999 @Override
1000 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -07001001 // TODO: watch for package upgrades to invalidate cache; see 7206643
1002 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -07001003 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
1004 invalidateHeaders();
1005 }
1006
Amith Yamasani5203bdf2010-11-04 09:59:44 -07001007 /*
1008 * Settings subclasses for launching independently.
1009 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001010 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1011 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1012 public static class TetherSettingsActivity extends Settings { /* empty */ }
1013 public static class VpnSettingsActivity extends Settings { /* empty */ }
1014 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1015 public static class StorageSettingsActivity extends Settings { /* empty */ }
1016 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001017 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001018 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001019 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001020 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001021 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001022 public static class LocalePickerActivity extends Settings { /* empty */ }
1023 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1024 public static class SoundSettingsActivity extends Settings { /* empty */ }
1025 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1026 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1027 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1028 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Dianne Hackborna522a8e2013-01-15 19:02:05 -08001029 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001030 public static class StorageUseActivity extends Settings { /* empty */ }
1031 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1032 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001033 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001034 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001035 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001036 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001037 public static class RunningServicesActivity extends Settings { /* empty */ }
1038 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1039 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1040 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1041 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1042 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1043 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1044 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001045 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001046 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001047 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001048 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001049 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001050 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001051 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001052 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001053 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001054 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001055 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001056 public static class PrintSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001057}