blob: bcfffcb59acf1adb423825a58035ef3d9b158d78 [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;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090022import android.content.BroadcastReceiver;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080023import android.content.ComponentName;
Gilles Debunnee78c1872011-06-20 15:00:07 -070024import android.content.Context;
Amith Yamasani379d9b02010-09-27 12:03:59 -070025import android.content.Intent;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090026import android.content.IntentFilter;
Dianne Hackborncaefa9b2012-10-10 15:05:42 -070027import android.content.SharedPreferences;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070028import android.content.pm.ActivityInfo;
Christopher Tatee238a472013-08-27 14:21:46 -070029import android.content.pm.ApplicationInfo;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070030import android.content.pm.PackageManager;
31import android.content.pm.PackageManager.NameNotFoundException;
Christopher Tatee238a472013-08-27 14:21:46 -070032import android.content.pm.ResolveInfo;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070033import android.graphics.drawable.Drawable;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070034import android.os.Bundle;
Jeff Sharkey34e964d2012-04-21 15:41:48 -070035import android.os.INetworkManagementService;
36import android.os.RemoteException;
37import android.os.ServiceManager;
Dianne Hackbornbb06a422012-08-16 11:01:57 -070038import android.os.UserHandle;
Jeff Sharkey44202462012-09-19 13:13:45 -070039import android.os.UserManager;
Amith Yamasania4379d62011-07-22 10:34:58 -070040import android.preference.Preference;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070041import android.preference.PreferenceActivity;
Amith Yamasania4379d62011-07-22 10:34:58 -070042import android.preference.PreferenceFragment;
Gilles Debunnee78c1872011-06-20 15:00:07 -070043import android.text.TextUtils;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080044import android.util.Log;
Gilles Debunnee78c1872011-06-20 15:00:07 -070045import android.view.LayoutInflater;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080046import android.view.View;
47import android.view.View.OnClickListener;
Gilles Debunnee78c1872011-06-20 15:00:07 -070048import android.view.ViewGroup;
49import android.widget.ArrayAdapter;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080050import android.widget.Button;
Gilles Debunnee78c1872011-06-20 15:00:07 -070051import android.widget.ImageView;
52import android.widget.ListAdapter;
53import android.widget.Switch;
54import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080055
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080056import com.android.internal.util.ArrayUtils;
Amith Yamasania677ee22013-07-26 13:38:41 -070057import com.android.settings.accessibility.AccessibilitySettings;
Alan Viverette341ff662013-07-18 17:49:33 -070058import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
Alan Viverette9b625f02013-09-11 13:03:14 -070059import com.android.settings.accessibility.ToggleCaptioningPreferenceFragment;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080060import com.android.settings.accounts.AccountSyncSettings;
61import com.android.settings.accounts.AuthenticatorHelper;
62import com.android.settings.accounts.ManageAccountsSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070063import com.android.settings.applications.AppOpsSummary;
64import com.android.settings.applications.ManageApplications;
Dianne Hackbornc6d658e2013-08-08 12:57:53 -070065import com.android.settings.applications.ProcessStatsUi;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080066import com.android.settings.bluetooth.BluetoothEnabler;
67import com.android.settings.bluetooth.BluetoothSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070068import com.android.settings.deviceinfo.Memory;
69import com.android.settings.deviceinfo.UsbSettings;
70import com.android.settings.fuelgauge.PowerUsageSummary;
71import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
Amith Yamasani3a14ae22013-08-30 15:43:44 -070072import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070073import com.android.settings.inputmethod.SpellCheckersSettings;
74import com.android.settings.inputmethod.UserDictionaryList;
Amith Yamasanie9904202013-08-01 10:26:14 -070075import com.android.settings.location.LocationSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070076import com.android.settings.nfc.AndroidBeam;
Martijn Coenen53083ab2013-08-09 13:37:38 -070077import com.android.settings.nfc.PaymentSettings;
Svetoslav2d531652013-09-03 21:32:40 -070078import com.android.settings.print.PrintServiceSettingsFragment;
79import com.android.settings.print.PrintSettingsFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070080import com.android.settings.tts.TextToSpeechSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070081import com.android.settings.users.UserSettings;
82import com.android.settings.vpn2.VpnSettings;
Jeff Sharkey0c3634c2013-02-20 12:35:16 -080083import com.android.settings.wfd.WifiDisplaySettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070084import com.android.settings.wifi.AdvancedWifiSettings;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080085import com.android.settings.wifi.WifiEnabler;
86import com.android.settings.wifi.WifiSettings;
87import com.android.settings.wifi.p2p.WifiP2pSettings;
88
Gilles Debunnee78c1872011-06-20 15:00:07 -070089import java.util.ArrayList;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070090import java.util.Collections;
91import java.util.Comparator;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070092import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070093import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -070094
95/**
96 * Top-level settings activity to handle single pane and double pane UI layout.
97 */
Amith Yamasani56821db2012-06-05 13:20:45 -070098public class Settings extends PreferenceActivity
99 implements ButtonBarHandler, OnAccountsUpdateListener {
Amith Yamasanid7993472010-08-18 13:59:28 -0700100
Gilles Debunnee78c1872011-06-20 15:00:07 -0700101 private static final String LOG_TAG = "Settings";
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700102
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700103 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700104 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700105 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700106 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800107 private static final String META_DATA_KEY_PARENT_TITLE =
108 "com.android.settings.PARENT_FRAGMENT_TITLE";
109 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
110 "com.android.settings.PARENT_FRAGMENT_CLASS";
111
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800112 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700113
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800114 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
115 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700116
117 private String mFragmentClass;
118 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -0800119 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800120 private Header mCurrentHeader;
121 private Header mParentHeader;
122 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700123
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700124 // Show only these settings for restricted users
125 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700126 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700127 R.id.wifi_settings,
128 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700129 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700130 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700131 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700132 R.id.sound_settings,
133 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700134 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700135 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700136 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700137 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700138 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700139 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700140 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700141 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700142 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700143 R.id.account_add,
144 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700145 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700146 R.id.about_settings,
Svetoslav Ganovd4c7b492013-06-11 21:15:11 -0700147 R.id.accessibility_settings,
Martijn Coenen26515da2013-08-01 18:13:33 -0700148 R.id.print_settings,
Christopher Tatee238a472013-08-27 14:21:46 -0700149 R.id.nfc_payment_settings,
150 R.id.home_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700151 };
152
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700153 private SharedPreferences mDevelopmentPreferences;
154 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
155
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700156 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700157
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700158 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
159
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700160 private AuthenticatorHelper mAuthenticatorHelper;
161 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700162 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700163
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900164 private boolean mBatteryPresent = true;
165 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
166
167 @Override
168 public void onReceive(Context context, Intent intent) {
169 String action = intent.getAction();
170 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
171 boolean batteryPresent = Utils.isBatteryPresent(intent);
172
173 if (mBatteryPresent != batteryPresent) {
174 mBatteryPresent = batteryPresent;
175 invalidateHeaders();
176 }
177 }
178 }
179 };
180
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700181 @Override
182 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800183 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
184 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700185 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700186
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700187 mAuthenticatorHelper = new AuthenticatorHelper();
188 mAuthenticatorHelper.updateAuthDescriptions(this);
189 mAuthenticatorHelper.onAccountsUpdated(this, null);
190
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700191 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
192 Context.MODE_PRIVATE);
193
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700194 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800195 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700196 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800197 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700198
Gilles Debunne3661b622011-06-27 11:19:16 -0700199 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700200 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800201 // Force the title so that it doesn't get overridden by a direct launch of
202 // a specific settings screen.
203 setTitle(R.string.settings_label);
204 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800205
206 // Retrieve any saved state
207 if (savedInstanceState != null) {
208 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
209 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
210 }
211
212 // If the current header was saved, switch to it
213 if (savedInstanceState != null && mCurrentHeader != null) {
214 //switchToHeaderLocal(mCurrentHeader);
215 showBreadCrumbs(mCurrentHeader.title, null);
216 }
217
218 if (mParentHeader != null) {
219 setParentTitle(mParentHeader.title, null, new OnClickListener() {
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400220 @Override
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800221 public void onClick(View v) {
222 switchToParent(mParentHeader.fragment);
223 }
224 });
225 }
Gilles Debunnedc7101f2011-06-27 12:00:49 -0700226
Amith Yamasani3d384f42012-05-11 15:22:04 -0700227 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
228 if (onIsMultiPane()) {
229 getActionBar().setDisplayHomeAsUpEnabled(false);
230 getActionBar().setHomeButtonEnabled(false);
231 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800232 }
233
234 @Override
235 protected void onSaveInstanceState(Bundle outState) {
236 super.onSaveInstanceState(outState);
237
238 // Save the current fragment, if it is the same as originally launched
239 if (mCurrentHeader != null) {
240 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
241 }
242 if (mParentHeader != null) {
243 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
244 }
245 }
246
Gilles Debunnee78c1872011-06-20 15:00:07 -0700247 @Override
248 public void onResume() {
249 super.onResume();
250
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700251 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
252 @Override
253 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
254 invalidateHeaders();
255 }
256 };
257 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
258 mDevelopmentPreferencesListener);
259
Gilles Debunnee78c1872011-06-20 15:00:07 -0700260 ListAdapter listAdapter = getListAdapter();
261 if (listAdapter instanceof HeaderAdapter) {
262 ((HeaderAdapter) listAdapter).resume();
263 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700264 invalidateHeaders();
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900265
266 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700267 }
268
269 @Override
270 public void onPause() {
271 super.onPause();
272
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900273 unregisterReceiver(mBatteryInfoReceiver);
274
Gilles Debunnee78c1872011-06-20 15:00:07 -0700275 ListAdapter listAdapter = getListAdapter();
276 if (listAdapter instanceof HeaderAdapter) {
277 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700278 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700279
280 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
281 mDevelopmentPreferencesListener);
282 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700283 }
284
285 @Override
286 public void onDestroy() {
287 super.onDestroy();
288 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700289 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700290 }
291 }
292
Amith Yamasani56f51a82013-08-05 10:07:23 -0700293 @Override
294 public boolean onIsMultiPane() {
295 return false;
296 }
297
Amith Yamasania677ee22013-07-26 13:38:41 -0700298 private static final String[] ENTRY_FRAGMENTS = {
299 WirelessSettings.class.getName(),
300 WifiSettings.class.getName(),
301 AdvancedWifiSettings.class.getName(),
302 BluetoothSettings.class.getName(),
303 TetherSettings.class.getName(),
304 WifiP2pSettings.class.getName(),
305 VpnSettings.class.getName(),
306 DateTimeSettings.class.getName(),
307 LocalePicker.class.getName(),
308 InputMethodAndLanguageSettings.class.getName(),
309 SpellCheckersSettings.class.getName(),
310 UserDictionaryList.class.getName(),
311 UserDictionarySettings.class.getName(),
312 SoundSettings.class.getName(),
313 DisplaySettings.class.getName(),
314 DeviceInfoSettings.class.getName(),
315 ManageApplications.class.getName(),
Dianne Hackbornc6d658e2013-08-08 12:57:53 -0700316 ProcessStatsUi.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700317 NotificationStation.class.getName(),
318 AppOpsSummary.class.getName(),
319 LocationSettings.class.getName(),
320 SecuritySettings.class.getName(),
321 PrivacySettings.class.getName(),
322 DeviceAdminSettings.class.getName(),
323 AccessibilitySettings.class.getName(),
Alan Viverette9b625f02013-09-11 13:03:14 -0700324 ToggleCaptioningPreferenceFragment.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700325 TextToSpeechSettings.class.getName(),
326 Memory.class.getName(),
327 DevelopmentSettings.class.getName(),
328 UsbSettings.class.getName(),
329 AndroidBeam.class.getName(),
330 WifiDisplaySettings.class.getName(),
331 PowerUsageSummary.class.getName(),
332 AccountSyncSettings.class.getName(),
333 CryptKeeperSettings.class.getName(),
334 DataUsageSummary.class.getName(),
335 DreamSettings.class.getName(),
336 UserSettings.class.getName(),
337 NotificationAccessSettings.class.getName(),
Amith Yamasaniee226f92013-08-05 11:02:16 -0700338 ManageAccountsSettings.class.getName(),
Svetoslav2d531652013-09-03 21:32:40 -0700339 PrintSettingsFragment.class.getName(),
Martijn Coenen53083ab2013-08-09 13:37:38 -0700340 TrustedCredentialsSettings.class.getName(),
Amith Yamasani3a14ae22013-08-30 15:43:44 -0700341 PaymentSettings.class.getName(),
342 KeyboardLayoutPickerFragment.class.getName()
Amith Yamasania677ee22013-07-26 13:38:41 -0700343 };
344
345 @Override
346 protected boolean isValidFragment(String fragmentName) {
347 // Almost all fragments are wrapped in this,
348 // except for a few that have their own activities.
349 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
350 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
351 }
352 return false;
353 }
354
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800355 private void switchToHeaderLocal(Header header) {
356 mInLocalHeaderSwitch = true;
357 switchToHeader(header);
358 mInLocalHeaderSwitch = false;
359 }
360
361 @Override
362 public void switchToHeader(Header header) {
363 if (!mInLocalHeaderSwitch) {
364 mCurrentHeader = null;
365 mParentHeader = null;
366 }
367 super.switchToHeader(header);
368 }
369
370 /**
371 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800372 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800373 */
374 private void switchToParent(String className) {
375 final ComponentName cn = new ComponentName(this, className);
376 try {
377 final PackageManager pm = getPackageManager();
378 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
379
380 if (parentInfo != null && parentInfo.metaData != null) {
381 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
382 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
383 Header parentHeader = new Header();
384 parentHeader.fragment = fragmentClass;
385 parentHeader.title = fragmentTitle;
386 mCurrentHeader = parentHeader;
387
388 switchToHeaderLocal(parentHeader);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700389 highlightHeader(mTopLevelHeaderId);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800390
391 mParentHeader = new Header();
392 mParentHeader.fragment
393 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
394 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
395 }
396 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700397 Log.w(LOG_TAG, "Could not find parent activity : " + className);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800398 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700399 }
400
Amith Yamasani3965ae62010-11-15 14:45:19 -0800401 @Override
402 public void onNewIntent(Intent intent) {
403 super.onNewIntent(intent);
404
405 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700406 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
407 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
408 switchToHeaderLocal(mFirstHeader);
409 }
410 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800411 }
412 }
413
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700414 private void highlightHeader(int id) {
415 if (id != 0) {
416 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700417 if (index != null) {
418 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700419 if (isMultiPane()) {
420 getListView().smoothScrollToPosition(index);
421 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700422 }
423 }
424 }
425
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700426 @Override
427 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700428 Intent superIntent = super.getIntent();
429 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700430 // This is called from super.onCreate, isMultiPane() is not yet reliable
431 // Do not use onIsHidingHeaders either, which relies itself on this method
432 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700433 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700434 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700435 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700436 if (args != null) {
437 args = new Bundle(args);
438 } else {
439 args = new Bundle();
440 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700441 args.putParcelable("intent", superIntent);
442 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700443 return modIntent;
444 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700445 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700446 }
447
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700448 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700449 * Checks if the component name in the intent is different from the Settings class and
450 * returns the class name to load as a fragment.
451 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700452 protected String getStartingFragmentClass(Intent intent) {
453 if (mFragmentClass != null) return mFragmentClass;
454
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700455 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700456 if (intentClass.equals(getClass().getName())) return null;
457
Dianne Hackbornee293792010-11-01 12:32:33 -0700458 if ("com.android.settings.ManageApplications".equals(intentClass)
459 || "com.android.settings.RunningServices".equals(intentClass)
460 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700461 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700462 intentClass = com.android.settings.applications.ManageApplications.class.getName();
463 }
464
Amith Yamasani379d9b02010-09-27 12:03:59 -0700465 return intentClass;
466 }
467
468 /**
469 * Override initial header when an activity-alias is causing Settings to be launched
470 * for a specific fragment encoded in the android:name parameter.
471 */
472 @Override
473 public Header onGetInitialHeader() {
474 String fragmentClass = getStartingFragmentClass(super.getIntent());
475 if (fragmentClass != null) {
476 Header header = new Header();
477 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800478 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700479 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800480 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700481 return header;
482 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700483
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700484 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700485 }
486
Dianne Hackbornb7258182011-03-15 16:23:55 -0700487 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700488 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
489 int titleRes, int shortTitleRes) {
490 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
491 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700492
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800493 // Some fragments want split ActionBar; these should stay in sync with
494 // uiOptions for fragments also defined as activities in manifest.
495 if (WifiSettings.class.getName().equals(fragmentName) ||
496 WifiP2pSettings.class.getName().equals(fragmentName) ||
Jeff Sharkey0c3634c2013-02-20 12:35:16 -0800497 WifiDisplaySettings.class.getName().equals(fragmentName) ||
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800498 BluetoothSettings.class.getName().equals(fragmentName) ||
499 DreamSettings.class.getName().equals(fragmentName) ||
Lifu Tangd5fbbc42013-08-01 17:23:10 -0700500 LocationSettings.class.getName().equals(fragmentName) ||
Svetoslav2d531652013-09-03 21:32:40 -0700501 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
502 PrintSettingsFragment.class.getName().equals(fragmentName) ||
503 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800504 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700505 }
506
Dianne Hackbornb7258182011-03-15 16:23:55 -0700507 intent.setClass(this, SubSettings.class);
508 return intent;
509 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700510
Amith Yamasani379d9b02010-09-27 12:03:59 -0700511 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700512 * Populate the activity with the top-level headers.
513 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700514 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700515 public void onBuildHeaders(List<Header> headers) {
516 loadHeadersFromResource(R.xml.settings_headers, headers);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700517 updateHeaderList(headers);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700518 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700519
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700520 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700521 final boolean showDev = mDevelopmentPreferences.getBoolean(
522 DevelopmentSettings.PREF_SHOW,
523 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700524 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400525
526 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700527 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700528 while (i < target.size()) {
529 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700530 // Ids are integers, so downcasting
531 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400532 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700533 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700534 } else if (id == R.id.wifi_settings) {
535 // Remove WiFi Settings if WiFi service is not available.
536 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700537 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700538 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700539 } else if (id == R.id.bluetooth_settings) {
540 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700541 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700542 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700543 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700544 } else if (id == R.id.data_usage_settings) {
545 // Remove data usage when kernel module not enabled
546 final INetworkManagementService netManager = INetworkManagementService.Stub
547 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
548 try {
549 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700550 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700551 }
552 } catch (RemoteException e) {
553 // ignored
554 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900555 } else if (id == R.id.battery_settings) {
556 // Remove battery settings when battery is not available. (e.g. TV)
557
558 if (!mBatteryPresent) {
559 target.remove(i);
560 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700561 } else if (id == R.id.account_settings) {
562 int headerIndex = i + 1;
563 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700564 } else if (id == R.id.home_settings) {
565 updateHomeSettingHeaders(header);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700566 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700567 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700568 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700569 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700570 target.remove(i);
571 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700572 } else if (id == R.id.nfc_payment_settings) {
573 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HCE)) {
574 target.remove(i);
575 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700576 } else if (id == R.id.development_settings) {
577 if (!showDev) {
578 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700579 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400580 } else if (id == R.id.account_add) {
581 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
582 target.remove(i);
583 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700584 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700585
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900586 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700587 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700588 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700589 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700590 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700591
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700592 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900593 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800594 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700595 if (mFirstHeader == null &&
596 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
597 mFirstHeader = header;
598 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700599 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700600 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700601 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700602 }
603 }
604
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700605 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
606 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
607 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
608 for (String accountType : accountTypes) {
609 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700610 if (label == null) {
611 continue;
612 }
613
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700614 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
615 boolean skipToAccount = accounts.length == 1
616 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700617 Header accHeader = new Header();
618 accHeader.title = label;
619 if (accHeader.extras == null) {
620 accHeader.extras = new Bundle();
621 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700622 if (skipToAccount) {
623 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
624 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
625 accHeader.fragment = AccountSyncSettings.class.getName();
626 accHeader.fragmentArguments = new Bundle();
627 // Need this for the icon
628 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
629 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
630 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
631 accounts[0]);
632 } else {
633 accHeader.breadCrumbTitle = label;
634 accHeader.breadCrumbShortTitle = label;
635 accHeader.fragment = ManageAccountsSettings.class.getName();
636 accHeader.fragmentArguments = new Bundle();
637 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
638 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
639 accountType);
640 if (!isMultiPane()) {
641 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
642 label.toString());
643 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700644 }
645 accountHeaders.add(accHeader);
646 }
647
648 // Sort by label
649 Collections.sort(accountHeaders, new Comparator<Header>() {
650 @Override
651 public int compare(Header h1, Header h2) {
652 return h1.title.toString().compareTo(h2.title.toString());
653 }
654 });
655
656 for (Header header : accountHeaders) {
657 target.add(headerIndex++, header);
658 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700659 if (!mListeningToAccountUpdates) {
660 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
661 mListeningToAccountUpdates = true;
662 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700663 return headerIndex;
664 }
665
Christopher Tatee238a472013-08-27 14:21:46 -0700666 private boolean isSystemApp(ResolveInfo ri) {
667 return ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
668 }
669
670 private void updateHomeSettingHeaders(Header header) {
671 final PackageManager pm = getPackageManager();
672 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
673 try {
674 ComponentName currentHome = pm.getHomeActivities(homeApps);
675 ResolveInfo iconSource = null;
676 if (currentHome == null) {
677 // no current default, so find the system home app and use that
678 for (int which = 0; which < homeApps.size(); which++) {
679 ResolveInfo ri = homeApps.get(which);
680 if (isSystemApp(ri)) {
681 iconSource = ri;
682 break;
683 }
684 }
685 } else {
686 // find the current-home entry in the returned set
687 for (int which = 0; which < homeApps.size(); which++) {
688 ResolveInfo ri = homeApps.get(which);
689 ComponentName riName = new ComponentName(ri.activityInfo.packageName,
690 ri.activityInfo.name);
691 if (riName.equals(currentHome)) {
692 iconSource = ri;
693 break;
694 }
695 }
696 }
697 if (iconSource != null) {
698 if (header.extras == null) {
699 header.extras = new Bundle();
700 }
701 header.extras.putParcelable(HomeSettings.CURRENT_HOME, iconSource.activityInfo);
702 } else {
703 Log.v(LOG_TAG, "No home app icon found");
704 }
705 } catch (Exception e) {
706 // Can't look up the home activity; bail on configuring the icon
707 Log.w(LOG_TAG, "Problem looking up home activity!", e);
708 }
709 }
710
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700711 private void getMetaData() {
712 try {
713 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
714 PackageManager.GET_META_DATA);
715 if (ai == null || ai.metaData == null) return;
716 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
717 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700718
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800719 // Check if it has a parent specified and create a Header object
720 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
721 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
722 if (parentFragmentClass != null) {
723 mParentHeader = new Header();
724 mParentHeader.fragment = parentFragmentClass;
725 if (parentHeaderTitleRes != 0) {
726 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
727 }
728 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700729 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700730 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700731 }
732 }
733
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800734 @Override
735 public boolean hasNextButton() {
736 return super.hasNextButton();
737 }
738
739 @Override
740 public Button getNextButton() {
741 return super.getNextButton();
742 }
743
Gilles Debunnee78c1872011-06-20 15:00:07 -0700744 private static class HeaderAdapter extends ArrayAdapter<Header> {
745 static final int HEADER_TYPE_CATEGORY = 0;
746 static final int HEADER_TYPE_NORMAL = 1;
747 static final int HEADER_TYPE_SWITCH = 2;
748 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;
749
750 private final WifiEnabler mWifiEnabler;
751 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700752 private AuthenticatorHelper mAuthHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700753
754 private static class HeaderViewHolder {
755 ImageView icon;
756 TextView title;
757 TextView summary;
758 Switch switch_;
759 }
760
761 private LayoutInflater mInflater;
762
763 static int getHeaderType(Header header) {
764 if (header.fragment == null && header.intent == null) {
765 return HEADER_TYPE_CATEGORY;
766 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
767 return HEADER_TYPE_SWITCH;
768 } else {
769 return HEADER_TYPE_NORMAL;
770 }
771 }
772
773 @Override
774 public int getItemViewType(int position) {
775 Header header = getItem(position);
776 return getHeaderType(header);
777 }
778
779 @Override
780 public boolean areAllItemsEnabled() {
781 return false; // because of categories
782 }
783
784 @Override
785 public boolean isEnabled(int position) {
786 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
787 }
788
789 @Override
790 public int getViewTypeCount() {
791 return HEADER_TYPE_COUNT;
792 }
793
794 @Override
795 public boolean hasStableIds() {
796 return true;
797 }
798
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700799 public HeaderAdapter(Context context, List<Header> objects,
800 AuthenticatorHelper authenticatorHelper) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700801 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700802
803 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700804 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700805
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700806 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700807 // Switches inflated from their layouts. Must be done before adapter is set in super
808 mWifiEnabler = new WifiEnabler(context, new Switch(context));
809 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
810 }
811
812 @Override
813 public View getView(int position, View convertView, ViewGroup parent) {
814 HeaderViewHolder holder;
815 Header header = getItem(position);
816 int headerType = getHeaderType(header);
817 View view = null;
818
819 if (convertView == null) {
820 holder = new HeaderViewHolder();
821 switch (headerType) {
822 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700823 view = new TextView(getContext(), null,
824 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700825 holder.title = (TextView) view;
826 break;
827
828 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700829 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
830 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700831 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700832 holder.title = (TextView)
833 view.findViewById(com.android.internal.R.id.title);
834 holder.summary = (TextView)
835 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700836 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
837 break;
838
839 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700840 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700841 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700842 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700843 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700844 holder.title = (TextView)
845 view.findViewById(com.android.internal.R.id.title);
846 holder.summary = (TextView)
847 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700848 break;
849 }
850 view.setTag(holder);
851 } else {
852 view = convertView;
853 holder = (HeaderViewHolder) view.getTag();
854 }
855
856 // All view fields must be updated every time, because the view may be recycled
857 switch (headerType) {
858 case HEADER_TYPE_CATEGORY:
859 holder.title.setText(header.getTitle(getContext().getResources()));
860 break;
861
862 case HEADER_TYPE_SWITCH:
863 // Would need a different treatment if the main menu had more switches
864 if (header.id == R.id.wifi_settings) {
865 mWifiEnabler.setSwitch(holder.switch_);
866 } else {
867 mBluetoothEnabler.setSwitch(holder.switch_);
868 }
869 // No break, fall through on purpose to update common fields
870
871 //$FALL-THROUGH$
872 case HEADER_TYPE_NORMAL:
Christopher Tatee238a472013-08-27 14:21:46 -0700873 if (header.extras != null &&
874 header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700875 String accType = header.extras.getString(
876 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700877 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
Christopher Tatee238a472013-08-27 14:21:46 -0700878 setHeaderIcon(holder, icon);
879 } else if (header.extras != null &&
880 header.extras.containsKey(HomeSettings.CURRENT_HOME)) {
881 ActivityInfo ai = header.extras.getParcelable(HomeSettings.CURRENT_HOME);
882 Drawable icon = ai.loadIcon(getContext().getPackageManager());
883 setHeaderIcon(holder, icon);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700884 } else {
885 holder.icon.setImageResource(header.iconRes);
886 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700887 holder.title.setText(header.getTitle(getContext().getResources()));
888 CharSequence summary = header.getSummary(getContext().getResources());
889 if (!TextUtils.isEmpty(summary)) {
890 holder.summary.setVisibility(View.VISIBLE);
891 holder.summary.setText(summary);
892 } else {
893 holder.summary.setVisibility(View.GONE);
894 }
895 break;
896 }
897
898 return view;
899 }
900
Christopher Tatee238a472013-08-27 14:21:46 -0700901 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
902 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
903 lp.width = getContext().getResources().getDimensionPixelSize(
904 R.dimen.header_icon_width);
905 lp.height = lp.width;
906 holder.icon.setLayoutParams(lp);
907 holder.icon.setImageDrawable(icon);
908 }
909
Gilles Debunnee78c1872011-06-20 15:00:07 -0700910 public void resume() {
911 mWifiEnabler.resume();
912 mBluetoothEnabler.resume();
913 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700914
Gilles Debunnee78c1872011-06-20 15:00:07 -0700915 public void pause() {
916 mWifiEnabler.pause();
917 mBluetoothEnabler.pause();
918 }
919 }
920
921 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700922 public void onHeaderClick(Header header, int position) {
923 boolean revert = false;
924 if (header.id == R.id.account_add) {
925 revert = true;
926 }
927
928 super.onHeaderClick(header, position);
929
930 if (revert && mLastHeader != null) {
931 highlightHeader((int) mLastHeader.id);
932 } else {
933 mLastHeader = header;
934 }
935 }
936
937 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700938 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
939 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800940 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700941 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800942 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -0700943 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
944 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -0700945 if (UserManager.get(this).isLinkedUser()) {
946 titleRes = R.string.profile_info_settings_title;
947 } else {
948 titleRes = R.string.user_info_settings_title;
949 }
Amith Yamasania4379d62011-07-22 10:34:58 -0700950 }
Jean Chalard7dabe452012-05-10 18:08:07 +0900951 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
952 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -0700953 return true;
954 }
955
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400956 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -0700957 public boolean shouldUpRecreateTask(Intent targetIntent) {
958 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
959 }
960
Amith Yamasania4379d62011-07-22 10:34:58 -0700961 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700962 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700963 if (adapter == null) {
964 super.setListAdapter(null);
965 } else {
966 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700967 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700968 }
969
Amith Yamasani56821db2012-06-05 13:20:45 -0700970 @Override
971 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -0700972 // TODO: watch for package upgrades to invalidate cache; see 7206643
973 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -0700974 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
975 invalidateHeaders();
976 }
977
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700978 /*
979 * Settings subclasses for launching independently.
980 */
Gilles Debunnee78c1872011-06-20 15:00:07 -0700981 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
982 public static class WirelessSettingsActivity extends Settings { /* empty */ }
983 public static class TetherSettingsActivity extends Settings { /* empty */ }
984 public static class VpnSettingsActivity extends Settings { /* empty */ }
985 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
986 public static class StorageSettingsActivity extends Settings { /* empty */ }
987 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -0700988 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700989 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -0700990 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700991 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +0900992 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700993 public static class LocalePickerActivity extends Settings { /* empty */ }
994 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
995 public static class SoundSettingsActivity extends Settings { /* empty */ }
996 public static class DisplaySettingsActivity extends Settings { /* empty */ }
997 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
998 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
999 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Dianne Hackborna522a8e2013-01-15 19:02:05 -08001000 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001001 public static class StorageUseActivity extends Settings { /* empty */ }
1002 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1003 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001004 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001005 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001006 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001007 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001008 public static class RunningServicesActivity extends Settings { /* empty */ }
1009 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1010 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1011 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1012 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1013 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1014 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1015 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001016 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001017 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001018 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001019 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001020 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001021 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001022 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001023 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001024 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001025 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001026 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001027 public static class PrintSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001028}