blob: 6b6e7043c5e319e73962c066cfd1772063f1e873 [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) {
567 updateHomeSettingHeaders(header);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700568 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700569 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700570 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700571 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700572 target.remove(i);
573 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700574 } else if (id == R.id.nfc_payment_settings) {
575 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HCE)) {
576 target.remove(i);
577 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700578 } else if (id == R.id.development_settings) {
579 if (!showDev) {
580 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700581 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400582 } else if (id == R.id.account_add) {
583 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
584 target.remove(i);
585 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700586 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700587
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900588 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700589 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700590 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700591 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700592 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700593
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700594 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900595 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800596 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700597 if (mFirstHeader == null &&
598 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
599 mFirstHeader = header;
600 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700601 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700602 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700603 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700604 }
605 }
606
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700607 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
608 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
609 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
610 for (String accountType : accountTypes) {
611 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700612 if (label == null) {
613 continue;
614 }
615
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700616 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
617 boolean skipToAccount = accounts.length == 1
618 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700619 Header accHeader = new Header();
620 accHeader.title = label;
621 if (accHeader.extras == null) {
622 accHeader.extras = new Bundle();
623 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700624 if (skipToAccount) {
625 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
626 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
627 accHeader.fragment = AccountSyncSettings.class.getName();
628 accHeader.fragmentArguments = new Bundle();
629 // Need this for the icon
630 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
631 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
632 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
633 accounts[0]);
634 } else {
635 accHeader.breadCrumbTitle = label;
636 accHeader.breadCrumbShortTitle = label;
637 accHeader.fragment = ManageAccountsSettings.class.getName();
638 accHeader.fragmentArguments = new Bundle();
639 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
640 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
641 accountType);
642 if (!isMultiPane()) {
643 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
644 label.toString());
645 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700646 }
647 accountHeaders.add(accHeader);
648 }
649
650 // Sort by label
651 Collections.sort(accountHeaders, new Comparator<Header>() {
652 @Override
653 public int compare(Header h1, Header h2) {
654 return h1.title.toString().compareTo(h2.title.toString());
655 }
656 });
657
658 for (Header header : accountHeaders) {
659 target.add(headerIndex++, header);
660 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700661 if (!mListeningToAccountUpdates) {
662 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
663 mListeningToAccountUpdates = true;
664 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700665 return headerIndex;
666 }
667
Christopher Tatee238a472013-08-27 14:21:46 -0700668 private boolean isSystemApp(ResolveInfo ri) {
669 return ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
670 }
671
672 private void updateHomeSettingHeaders(Header header) {
673 final PackageManager pm = getPackageManager();
674 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
675 try {
676 ComponentName currentHome = pm.getHomeActivities(homeApps);
677 ResolveInfo iconSource = null;
678 if (currentHome == null) {
679 // no current default, so find the system home app and use that
680 for (int which = 0; which < homeApps.size(); which++) {
681 ResolveInfo ri = homeApps.get(which);
682 if (isSystemApp(ri)) {
683 iconSource = ri;
684 break;
685 }
686 }
687 } else {
688 // find the current-home entry in the returned set
689 for (int which = 0; which < homeApps.size(); which++) {
690 ResolveInfo ri = homeApps.get(which);
691 ComponentName riName = new ComponentName(ri.activityInfo.packageName,
692 ri.activityInfo.name);
693 if (riName.equals(currentHome)) {
694 iconSource = ri;
695 break;
696 }
697 }
698 }
699 if (iconSource != null) {
700 if (header.extras == null) {
701 header.extras = new Bundle();
702 }
703 header.extras.putParcelable(HomeSettings.CURRENT_HOME, iconSource.activityInfo);
704 } else {
705 Log.v(LOG_TAG, "No home app icon found");
706 }
707 } catch (Exception e) {
708 // Can't look up the home activity; bail on configuring the icon
709 Log.w(LOG_TAG, "Problem looking up home activity!", e);
710 }
711 }
712
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700713 private void getMetaData() {
714 try {
715 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
716 PackageManager.GET_META_DATA);
717 if (ai == null || ai.metaData == null) return;
718 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
719 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700720
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800721 // Check if it has a parent specified and create a Header object
722 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
723 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
724 if (parentFragmentClass != null) {
725 mParentHeader = new Header();
726 mParentHeader.fragment = parentFragmentClass;
727 if (parentHeaderTitleRes != 0) {
728 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
729 }
730 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700731 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700732 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700733 }
734 }
735
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800736 @Override
737 public boolean hasNextButton() {
738 return super.hasNextButton();
739 }
740
741 @Override
742 public Button getNextButton() {
743 return super.getNextButton();
744 }
745
Gilles Debunnee78c1872011-06-20 15:00:07 -0700746 private static class HeaderAdapter extends ArrayAdapter<Header> {
747 static final int HEADER_TYPE_CATEGORY = 0;
748 static final int HEADER_TYPE_NORMAL = 1;
749 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400750 static final int HEADER_TYPE_BUTTON = 3;
751 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700752
753 private final WifiEnabler mWifiEnabler;
754 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700755 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400756 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700757
758 private static class HeaderViewHolder {
759 ImageView icon;
760 TextView title;
761 TextView summary;
762 Switch switch_;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400763 ImageButton button_;
764 View divider_;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700765 }
766
767 private LayoutInflater mInflater;
768
769 static int getHeaderType(Header header) {
770 if (header.fragment == null && header.intent == null) {
771 return HEADER_TYPE_CATEGORY;
772 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
773 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400774 } else if (header.id == R.id.security_settings) {
775 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700776 } else {
777 return HEADER_TYPE_NORMAL;
778 }
779 }
780
781 @Override
782 public int getItemViewType(int position) {
783 Header header = getItem(position);
784 return getHeaderType(header);
785 }
786
787 @Override
788 public boolean areAllItemsEnabled() {
789 return false; // because of categories
790 }
791
792 @Override
793 public boolean isEnabled(int position) {
794 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
795 }
796
797 @Override
798 public int getViewTypeCount() {
799 return HEADER_TYPE_COUNT;
800 }
801
802 @Override
803 public boolean hasStableIds() {
804 return true;
805 }
806
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700807 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400808 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700809 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700810
811 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700812 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700813
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700814 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700815 // Switches inflated from their layouts. Must be done before adapter is set in super
816 mWifiEnabler = new WifiEnabler(context, new Switch(context));
817 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400818 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700819 }
820
821 @Override
822 public View getView(int position, View convertView, ViewGroup parent) {
823 HeaderViewHolder holder;
824 Header header = getItem(position);
825 int headerType = getHeaderType(header);
826 View view = null;
827
828 if (convertView == null) {
829 holder = new HeaderViewHolder();
830 switch (headerType) {
831 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700832 view = new TextView(getContext(), null,
833 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700834 holder.title = (TextView) view;
835 break;
836
837 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700838 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
839 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700840 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700841 holder.title = (TextView)
842 view.findViewById(com.android.internal.R.id.title);
843 holder.summary = (TextView)
844 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700845 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
846 break;
847
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400848 case HEADER_TYPE_BUTTON:
849 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
850 false);
851 holder.icon = (ImageView) view.findViewById(R.id.icon);
852 holder.title = (TextView)
853 view.findViewById(com.android.internal.R.id.title);
854 holder.summary = (TextView)
855 view.findViewById(com.android.internal.R.id.summary);
856 holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget);
857 holder.divider_ = view.findViewById(R.id.divider);
858 break;
859
Gilles Debunnee78c1872011-06-20 15:00:07 -0700860 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700861 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700862 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700863 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700864 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700865 holder.title = (TextView)
866 view.findViewById(com.android.internal.R.id.title);
867 holder.summary = (TextView)
868 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700869 break;
870 }
871 view.setTag(holder);
872 } else {
873 view = convertView;
874 holder = (HeaderViewHolder) view.getTag();
875 }
876
877 // All view fields must be updated every time, because the view may be recycled
878 switch (headerType) {
879 case HEADER_TYPE_CATEGORY:
880 holder.title.setText(header.getTitle(getContext().getResources()));
881 break;
882
883 case HEADER_TYPE_SWITCH:
884 // Would need a different treatment if the main menu had more switches
885 if (header.id == R.id.wifi_settings) {
886 mWifiEnabler.setSwitch(holder.switch_);
887 } else {
888 mBluetoothEnabler.setSwitch(holder.switch_);
889 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400890 updateCommonHeaderView(header, holder);
891 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700892
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400893 case HEADER_TYPE_BUTTON:
894 if (header.id == R.id.security_settings) {
895 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
896 if (hasCert) {
897 holder.button_.setVisibility(View.VISIBLE);
898 holder.divider_.setVisibility(View.VISIBLE);
899 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
900 if (isManaged) {
901 holder.button_.setImageResource(R.drawable.ic_qs_certificate_info);
902 } else {
903 holder.button_.setImageResource(
904 android.R.drawable.stat_notify_error);
905 }
906 holder.button_.setOnClickListener(new OnClickListener() {
907 @Override
908 public void onClick(View v) {
909 Intent intent = new Intent(
910 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
911 getContext().startActivity(intent);
912 }
913 });
914 } else {
915 holder.button_.setVisibility(View.GONE);
916 holder.divider_.setVisibility(View.GONE);
917 }
918 }
919 updateCommonHeaderView(header, holder);
920 break;
921
Gilles Debunnee78c1872011-06-20 15:00:07 -0700922 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400923 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700924 break;
925 }
926
927 return view;
928 }
929
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400930 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
931 if (header.extras != null
932 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
933 String accType = header.extras.getString(
934 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
935 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
936 setHeaderIcon(holder, icon);
937 } else if (header.extras != null &&
938 header.extras.containsKey(HomeSettings.CURRENT_HOME)) {
939 ActivityInfo ai = header.extras.getParcelable(HomeSettings.CURRENT_HOME);
940 Drawable icon = ai.loadIcon(getContext().getPackageManager());
941 setHeaderIcon(holder, icon);
942 } else {
943 holder.icon.setImageResource(header.iconRes);
944 }
945 holder.title.setText(header.getTitle(getContext().getResources()));
946 CharSequence summary = header.getSummary(getContext().getResources());
947 if (!TextUtils.isEmpty(summary)) {
948 holder.summary.setVisibility(View.VISIBLE);
949 holder.summary.setText(summary);
950 } else {
951 holder.summary.setVisibility(View.GONE);
952 }
953 }
954
Christopher Tatee238a472013-08-27 14:21:46 -0700955 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
956 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
957 lp.width = getContext().getResources().getDimensionPixelSize(
958 R.dimen.header_icon_width);
959 lp.height = lp.width;
960 holder.icon.setLayoutParams(lp);
961 holder.icon.setImageDrawable(icon);
962 }
963
Gilles Debunnee78c1872011-06-20 15:00:07 -0700964 public void resume() {
965 mWifiEnabler.resume();
966 mBluetoothEnabler.resume();
967 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700968
Gilles Debunnee78c1872011-06-20 15:00:07 -0700969 public void pause() {
970 mWifiEnabler.pause();
971 mBluetoothEnabler.pause();
972 }
973 }
974
975 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700976 public void onHeaderClick(Header header, int position) {
977 boolean revert = false;
978 if (header.id == R.id.account_add) {
979 revert = true;
980 }
981
982 super.onHeaderClick(header, position);
983
984 if (revert && mLastHeader != null) {
985 highlightHeader((int) mLastHeader.id);
986 } else {
987 mLastHeader = header;
988 }
989 }
990
991 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700992 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
993 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800994 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700995 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800996 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -0700997 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
998 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -0700999 if (UserManager.get(this).isLinkedUser()) {
1000 titleRes = R.string.profile_info_settings_title;
1001 } else {
1002 titleRes = R.string.user_info_settings_title;
1003 }
Amith Yamasania4379d62011-07-22 10:34:58 -07001004 }
Jean Chalard7dabe452012-05-10 18:08:07 +09001005 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
1006 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -07001007 return true;
1008 }
1009
Maggie Benthall0c5a4012013-03-14 17:41:27 -04001010 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -07001011 public boolean shouldUpRecreateTask(Intent targetIntent) {
1012 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
1013 }
1014
Amith Yamasania4379d62011-07-22 10:34:58 -07001015 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -07001016 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -07001017 if (adapter == null) {
1018 super.setListAdapter(null);
1019 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -04001020 DevicePolicyManager dpm =
1021 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
1022 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -07001023 }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001024 }
1025
Amith Yamasani56821db2012-06-05 13:20:45 -07001026 @Override
1027 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -07001028 // TODO: watch for package upgrades to invalidate cache; see 7206643
1029 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -07001030 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
1031 invalidateHeaders();
1032 }
1033
Amith Yamasani5203bdf2010-11-04 09:59:44 -07001034 /*
1035 * Settings subclasses for launching independently.
1036 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001037 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1038 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1039 public static class TetherSettingsActivity extends Settings { /* empty */ }
1040 public static class VpnSettingsActivity extends Settings { /* empty */ }
1041 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1042 public static class StorageSettingsActivity extends Settings { /* empty */ }
1043 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001044 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001045 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001046 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001047 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001048 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001049 public static class LocalePickerActivity extends Settings { /* empty */ }
1050 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1051 public static class SoundSettingsActivity extends Settings { /* empty */ }
1052 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1053 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1054 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1055 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Dianne Hackborna522a8e2013-01-15 19:02:05 -08001056 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001057 public static class StorageUseActivity extends Settings { /* empty */ }
1058 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1059 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001060 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001061 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001062 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001063 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001064 public static class RunningServicesActivity extends Settings { /* empty */ }
1065 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1066 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1067 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1068 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1069 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1070 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1071 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001072 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001073 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001074 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001075 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001076 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001077 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001078 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001079 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001080 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001081 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001082 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001083 public static class PrintSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001084}