blob: e93fa186130b2450e560ed11b7b1495071fefb62 [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;
Christopher Tatee0d934f2013-10-01 12:32:27 -070022import android.app.Activity;
23import android.app.AlertDialog;
24import android.app.Dialog;
25import android.app.DialogFragment;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -040026import android.app.admin.DevicePolicyManager;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090027import android.content.BroadcastReceiver;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080028import android.content.ComponentName;
Gilles Debunnee78c1872011-06-20 15:00:07 -070029import android.content.Context;
Amith Yamasani379d9b02010-09-27 12:03:59 -070030import android.content.Intent;
Jaewan Kima3fe77b2013-06-04 21:17:40 +090031import android.content.IntentFilter;
Dianne Hackborncaefa9b2012-10-10 15:05:42 -070032import android.content.SharedPreferences;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070033import android.content.pm.ActivityInfo;
34import android.content.pm.PackageManager;
35import android.content.pm.PackageManager.NameNotFoundException;
Christopher Tatee238a472013-08-27 14:21:46 -070036import android.content.pm.ResolveInfo;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070037import android.graphics.drawable.Drawable;
Martijn Coenen81ab8172013-09-30 12:07:02 -070038import android.nfc.NfcAdapter;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070039import android.os.Bundle;
Jeff Sharkey34e964d2012-04-21 15:41:48 -070040import android.os.INetworkManagementService;
41import android.os.RemoteException;
42import android.os.ServiceManager;
Dianne Hackbornbb06a422012-08-16 11:01:57 -070043import android.os.UserHandle;
Jeff Sharkey44202462012-09-19 13:13:45 -070044import android.os.UserManager;
Amith Yamasania4379d62011-07-22 10:34:58 -070045import android.preference.Preference;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070046import android.preference.PreferenceActivity;
Amith Yamasania4379d62011-07-22 10:34:58 -070047import android.preference.PreferenceFragment;
Gilles Debunnee78c1872011-06-20 15:00:07 -070048import android.text.TextUtils;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080049import android.util.Log;
Gilles Debunnee78c1872011-06-20 15:00:07 -070050import android.view.LayoutInflater;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080051import android.view.View;
52import android.view.View.OnClickListener;
Gilles Debunnee78c1872011-06-20 15:00:07 -070053import android.view.ViewGroup;
54import android.widget.ArrayAdapter;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080055import android.widget.Button;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -040056import android.widget.ImageButton;
Gilles Debunnee78c1872011-06-20 15:00:07 -070057import android.widget.ImageView;
58import android.widget.ListAdapter;
59import android.widget.Switch;
60import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080061
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080062import com.android.internal.util.ArrayUtils;
Amith Yamasania677ee22013-07-26 13:38:41 -070063import com.android.settings.accessibility.AccessibilitySettings;
Alan Viverette341ff662013-07-18 17:49:33 -070064import com.android.settings.accessibility.ToggleAccessibilityServicePreferenceFragment;
Alan Viverette9b625f02013-09-11 13:03:14 -070065import com.android.settings.accessibility.ToggleCaptioningPreferenceFragment;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080066import com.android.settings.accounts.AccountSyncSettings;
67import com.android.settings.accounts.AuthenticatorHelper;
68import com.android.settings.accounts.ManageAccountsSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070069import com.android.settings.applications.AppOpsSummary;
70import com.android.settings.applications.ManageApplications;
Dianne Hackbornc6d658e2013-08-08 12:57:53 -070071import com.android.settings.applications.ProcessStatsUi;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080072import com.android.settings.bluetooth.BluetoothEnabler;
73import com.android.settings.bluetooth.BluetoothSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070074import com.android.settings.deviceinfo.Memory;
75import com.android.settings.deviceinfo.UsbSettings;
76import com.android.settings.fuelgauge.PowerUsageSummary;
77import com.android.settings.inputmethod.InputMethodAndLanguageSettings;
Amith Yamasani3a14ae22013-08-30 15:43:44 -070078import com.android.settings.inputmethod.KeyboardLayoutPickerFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070079import com.android.settings.inputmethod.SpellCheckersSettings;
80import com.android.settings.inputmethod.UserDictionaryList;
Amith Yamasanie9904202013-08-01 10:26:14 -070081import com.android.settings.location.LocationSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070082import com.android.settings.nfc.AndroidBeam;
Martijn Coenen53083ab2013-08-09 13:37:38 -070083import com.android.settings.nfc.PaymentSettings;
Svetoslavd9f156d2013-10-09 21:59:04 -070084import com.android.settings.print.PrintJobSettingsFragment;
Svetoslav2d531652013-09-03 21:32:40 -070085import com.android.settings.print.PrintServiceSettingsFragment;
86import com.android.settings.print.PrintSettingsFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070087import com.android.settings.tts.TextToSpeechSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070088import com.android.settings.users.UserSettings;
89import com.android.settings.vpn2.VpnSettings;
Jeff Sharkey0c3634c2013-02-20 12:35:16 -080090import com.android.settings.wfd.WifiDisplaySettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070091import com.android.settings.wifi.AdvancedWifiSettings;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080092import com.android.settings.wifi.WifiEnabler;
93import com.android.settings.wifi.WifiSettings;
94import com.android.settings.wifi.p2p.WifiP2pSettings;
95
Gilles Debunnee78c1872011-06-20 15:00:07 -070096import java.util.ArrayList;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070097import java.util.Collections;
98import java.util.Comparator;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070099import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700100import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -0700101
102/**
103 * Top-level settings activity to handle single pane and double pane UI layout.
104 */
Amith Yamasani56821db2012-06-05 13:20:45 -0700105public class Settings extends PreferenceActivity
106 implements ButtonBarHandler, OnAccountsUpdateListener {
Amith Yamasanid7993472010-08-18 13:59:28 -0700107
Gilles Debunnee78c1872011-06-20 15:00:07 -0700108 private static final String LOG_TAG = "Settings";
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700109
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700110 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700111 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700112 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700113 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800114 private static final String META_DATA_KEY_PARENT_TITLE =
115 "com.android.settings.PARENT_FRAGMENT_TITLE";
116 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
117 "com.android.settings.PARENT_FRAGMENT_CLASS";
118
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800119 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700120
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800121 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
122 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700123
Christopher Tatee0d934f2013-10-01 12:32:27 -0700124 static final int DIALOG_ONLY_ONE_HOME = 1;
125
126 private static boolean sShowNoHomeNotice = false;
127
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700128 private String mFragmentClass;
129 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -0800130 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800131 private Header mCurrentHeader;
132 private Header mParentHeader;
133 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700134
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700135 // Show only these settings for restricted users
136 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700137 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700138 R.id.wifi_settings,
139 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700140 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700141 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700142 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700143 R.id.sound_settings,
144 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700145 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700146 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700147 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700148 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700149 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700150 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700151 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700152 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700153 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700154 R.id.account_add,
155 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700156 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700157 R.id.about_settings,
Svetoslav Ganovd4c7b492013-06-11 21:15:11 -0700158 R.id.accessibility_settings,
Martijn Coenen26515da2013-08-01 18:13:33 -0700159 R.id.print_settings,
Christopher Tatee238a472013-08-27 14:21:46 -0700160 R.id.nfc_payment_settings,
161 R.id.home_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700162 };
163
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700164 private SharedPreferences mDevelopmentPreferences;
165 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
166
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700167 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700168
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700169 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
170
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700171 private AuthenticatorHelper mAuthenticatorHelper;
172 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700173 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700174
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900175 private boolean mBatteryPresent = true;
176 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
177
178 @Override
179 public void onReceive(Context context, Intent intent) {
180 String action = intent.getAction();
181 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
182 boolean batteryPresent = Utils.isBatteryPresent(intent);
183
184 if (mBatteryPresent != batteryPresent) {
185 mBatteryPresent = batteryPresent;
186 invalidateHeaders();
187 }
188 }
189 }
190 };
191
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700192 @Override
193 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800194 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
195 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700196 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700197
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700198 mAuthenticatorHelper = new AuthenticatorHelper();
199 mAuthenticatorHelper.updateAuthDescriptions(this);
200 mAuthenticatorHelper.onAccountsUpdated(this, null);
201
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700202 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
203 Context.MODE_PRIVATE);
204
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700205 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800206 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700207 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800208 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700209
Gilles Debunne3661b622011-06-27 11:19:16 -0700210 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700211 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800212 // Force the title so that it doesn't get overridden by a direct launch of
213 // a specific settings screen.
214 setTitle(R.string.settings_label);
215 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800216
217 // Retrieve any saved state
218 if (savedInstanceState != null) {
219 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
220 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
221 }
222
223 // If the current header was saved, switch to it
224 if (savedInstanceState != null && mCurrentHeader != null) {
225 //switchToHeaderLocal(mCurrentHeader);
226 showBreadCrumbs(mCurrentHeader.title, null);
227 }
228
229 if (mParentHeader != null) {
230 setParentTitle(mParentHeader.title, null, new OnClickListener() {
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400231 @Override
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800232 public void onClick(View v) {
233 switchToParent(mParentHeader.fragment);
234 }
235 });
236 }
Gilles Debunnedc7101f2011-06-27 12:00:49 -0700237
Amith Yamasani3d384f42012-05-11 15:22:04 -0700238 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
239 if (onIsMultiPane()) {
240 getActionBar().setDisplayHomeAsUpEnabled(false);
241 getActionBar().setHomeButtonEnabled(false);
242 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800243 }
244
245 @Override
246 protected void onSaveInstanceState(Bundle outState) {
247 super.onSaveInstanceState(outState);
248
249 // Save the current fragment, if it is the same as originally launched
250 if (mCurrentHeader != null) {
251 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
252 }
253 if (mParentHeader != null) {
254 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
255 }
256 }
257
Gilles Debunnee78c1872011-06-20 15:00:07 -0700258 @Override
259 public void onResume() {
260 super.onResume();
261
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700262 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
263 @Override
264 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
265 invalidateHeaders();
266 }
267 };
268 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
269 mDevelopmentPreferencesListener);
270
Gilles Debunnee78c1872011-06-20 15:00:07 -0700271 ListAdapter listAdapter = getListAdapter();
272 if (listAdapter instanceof HeaderAdapter) {
273 ((HeaderAdapter) listAdapter).resume();
274 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700275 invalidateHeaders();
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900276
277 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700278 }
279
280 @Override
281 public void onPause() {
282 super.onPause();
283
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900284 unregisterReceiver(mBatteryInfoReceiver);
285
Gilles Debunnee78c1872011-06-20 15:00:07 -0700286 ListAdapter listAdapter = getListAdapter();
287 if (listAdapter instanceof HeaderAdapter) {
288 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700289 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700290
291 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
292 mDevelopmentPreferencesListener);
293 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700294 }
295
296 @Override
297 public void onDestroy() {
298 super.onDestroy();
299 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700300 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700301 }
302 }
303
Amith Yamasani56f51a82013-08-05 10:07:23 -0700304 @Override
305 public boolean onIsMultiPane() {
306 return false;
307 }
308
Amith Yamasania677ee22013-07-26 13:38:41 -0700309 private static final String[] ENTRY_FRAGMENTS = {
310 WirelessSettings.class.getName(),
311 WifiSettings.class.getName(),
312 AdvancedWifiSettings.class.getName(),
313 BluetoothSettings.class.getName(),
314 TetherSettings.class.getName(),
315 WifiP2pSettings.class.getName(),
316 VpnSettings.class.getName(),
317 DateTimeSettings.class.getName(),
318 LocalePicker.class.getName(),
319 InputMethodAndLanguageSettings.class.getName(),
320 SpellCheckersSettings.class.getName(),
321 UserDictionaryList.class.getName(),
322 UserDictionarySettings.class.getName(),
323 SoundSettings.class.getName(),
324 DisplaySettings.class.getName(),
325 DeviceInfoSettings.class.getName(),
326 ManageApplications.class.getName(),
Dianne Hackbornc6d658e2013-08-08 12:57:53 -0700327 ProcessStatsUi.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700328 NotificationStation.class.getName(),
329 AppOpsSummary.class.getName(),
330 LocationSettings.class.getName(),
331 SecuritySettings.class.getName(),
332 PrivacySettings.class.getName(),
333 DeviceAdminSettings.class.getName(),
334 AccessibilitySettings.class.getName(),
Alan Viverette9b625f02013-09-11 13:03:14 -0700335 ToggleCaptioningPreferenceFragment.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700336 TextToSpeechSettings.class.getName(),
337 Memory.class.getName(),
338 DevelopmentSettings.class.getName(),
339 UsbSettings.class.getName(),
340 AndroidBeam.class.getName(),
341 WifiDisplaySettings.class.getName(),
342 PowerUsageSummary.class.getName(),
343 AccountSyncSettings.class.getName(),
344 CryptKeeperSettings.class.getName(),
345 DataUsageSummary.class.getName(),
346 DreamSettings.class.getName(),
347 UserSettings.class.getName(),
348 NotificationAccessSettings.class.getName(),
Amith Yamasaniee226f92013-08-05 11:02:16 -0700349 ManageAccountsSettings.class.getName(),
Svetoslav2d531652013-09-03 21:32:40 -0700350 PrintSettingsFragment.class.getName(),
Svetoslavd9f156d2013-10-09 21:59:04 -0700351 PrintJobSettingsFragment.class.getName(),
Martijn Coenen53083ab2013-08-09 13:37:38 -0700352 TrustedCredentialsSettings.class.getName(),
Amith Yamasani3a14ae22013-08-30 15:43:44 -0700353 PaymentSettings.class.getName(),
354 KeyboardLayoutPickerFragment.class.getName()
Amith Yamasania677ee22013-07-26 13:38:41 -0700355 };
356
357 @Override
358 protected boolean isValidFragment(String fragmentName) {
359 // Almost all fragments are wrapped in this,
360 // except for a few that have their own activities.
361 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
362 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
363 }
364 return false;
365 }
366
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800367 private void switchToHeaderLocal(Header header) {
368 mInLocalHeaderSwitch = true;
369 switchToHeader(header);
370 mInLocalHeaderSwitch = false;
371 }
372
373 @Override
374 public void switchToHeader(Header header) {
375 if (!mInLocalHeaderSwitch) {
376 mCurrentHeader = null;
377 mParentHeader = null;
378 }
379 super.switchToHeader(header);
380 }
381
382 /**
383 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800384 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800385 */
386 private void switchToParent(String className) {
387 final ComponentName cn = new ComponentName(this, className);
388 try {
389 final PackageManager pm = getPackageManager();
390 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
391
392 if (parentInfo != null && parentInfo.metaData != null) {
393 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
394 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
395 Header parentHeader = new Header();
396 parentHeader.fragment = fragmentClass;
397 parentHeader.title = fragmentTitle;
398 mCurrentHeader = parentHeader;
399
400 switchToHeaderLocal(parentHeader);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700401 highlightHeader(mTopLevelHeaderId);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800402
403 mParentHeader = new Header();
404 mParentHeader.fragment
405 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
406 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
407 }
408 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700409 Log.w(LOG_TAG, "Could not find parent activity : " + className);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800410 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700411 }
412
Amith Yamasani3965ae62010-11-15 14:45:19 -0800413 @Override
414 public void onNewIntent(Intent intent) {
415 super.onNewIntent(intent);
416
417 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700418 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
419 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
420 switchToHeaderLocal(mFirstHeader);
421 }
422 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800423 }
424 }
425
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700426 private void highlightHeader(int id) {
427 if (id != 0) {
428 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700429 if (index != null) {
430 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700431 if (isMultiPane()) {
432 getListView().smoothScrollToPosition(index);
433 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700434 }
435 }
436 }
437
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700438 @Override
439 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700440 Intent superIntent = super.getIntent();
441 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700442 // This is called from super.onCreate, isMultiPane() is not yet reliable
443 // Do not use onIsHidingHeaders either, which relies itself on this method
444 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700445 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700446 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700447 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700448 if (args != null) {
449 args = new Bundle(args);
450 } else {
451 args = new Bundle();
452 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700453 args.putParcelable("intent", superIntent);
454 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700455 return modIntent;
456 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700457 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700458 }
459
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700460 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700461 * Checks if the component name in the intent is different from the Settings class and
462 * returns the class name to load as a fragment.
463 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700464 protected String getStartingFragmentClass(Intent intent) {
465 if (mFragmentClass != null) return mFragmentClass;
466
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700467 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700468 if (intentClass.equals(getClass().getName())) return null;
469
Dianne Hackbornee293792010-11-01 12:32:33 -0700470 if ("com.android.settings.ManageApplications".equals(intentClass)
471 || "com.android.settings.RunningServices".equals(intentClass)
472 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700473 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700474 intentClass = com.android.settings.applications.ManageApplications.class.getName();
475 }
476
Amith Yamasani379d9b02010-09-27 12:03:59 -0700477 return intentClass;
478 }
479
480 /**
481 * Override initial header when an activity-alias is causing Settings to be launched
482 * for a specific fragment encoded in the android:name parameter.
483 */
484 @Override
485 public Header onGetInitialHeader() {
486 String fragmentClass = getStartingFragmentClass(super.getIntent());
487 if (fragmentClass != null) {
488 Header header = new Header();
489 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800490 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700491 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800492 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700493 return header;
494 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700495
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700496 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700497 }
498
Dianne Hackbornb7258182011-03-15 16:23:55 -0700499 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700500 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
501 int titleRes, int shortTitleRes) {
502 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
503 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700504
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800505 // Some fragments want split ActionBar; these should stay in sync with
506 // uiOptions for fragments also defined as activities in manifest.
507 if (WifiSettings.class.getName().equals(fragmentName) ||
508 WifiP2pSettings.class.getName().equals(fragmentName) ||
Jeff Sharkey0c3634c2013-02-20 12:35:16 -0800509 WifiDisplaySettings.class.getName().equals(fragmentName) ||
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800510 BluetoothSettings.class.getName().equals(fragmentName) ||
511 DreamSettings.class.getName().equals(fragmentName) ||
Lifu Tangd5fbbc42013-08-01 17:23:10 -0700512 LocationSettings.class.getName().equals(fragmentName) ||
Svetoslav2d531652013-09-03 21:32:40 -0700513 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
514 PrintSettingsFragment.class.getName().equals(fragmentName) ||
515 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800516 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700517 }
518
Dianne Hackbornb7258182011-03-15 16:23:55 -0700519 intent.setClass(this, SubSettings.class);
520 return intent;
521 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700522
Amith Yamasani379d9b02010-09-27 12:03:59 -0700523 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700524 * Populate the activity with the top-level headers.
525 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700526 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700527 public void onBuildHeaders(List<Header> headers) {
Amith Yamasani2972c012013-10-02 11:48:46 -0700528 if (!onIsHidingHeaders()) {
529 loadHeadersFromResource(R.xml.settings_headers, headers);
530 updateHeaderList(headers);
531 }
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700532 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700533
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700534 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700535 final boolean showDev = mDevelopmentPreferences.getBoolean(
536 DevelopmentSettings.PREF_SHOW,
537 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700538 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400539
540 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700541 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700542 while (i < target.size()) {
543 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700544 // Ids are integers, so downcasting
545 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400546 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700547 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700548 } else if (id == R.id.wifi_settings) {
549 // Remove WiFi Settings if WiFi service is not available.
550 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700551 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700552 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700553 } else if (id == R.id.bluetooth_settings) {
554 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700555 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700556 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700557 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700558 } else if (id == R.id.data_usage_settings) {
559 // Remove data usage when kernel module not enabled
560 final INetworkManagementService netManager = INetworkManagementService.Stub
561 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
562 try {
563 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700564 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700565 }
566 } catch (RemoteException e) {
567 // ignored
568 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900569 } else if (id == R.id.battery_settings) {
570 // Remove battery settings when battery is not available. (e.g. TV)
571
572 if (!mBatteryPresent) {
573 target.remove(i);
574 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700575 } else if (id == R.id.account_settings) {
576 int headerIndex = i + 1;
577 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700578 } else if (id == R.id.home_settings) {
Christopher Tate8243c9a2013-09-19 14:59:17 -0700579 if (!updateHomeSettingHeaders(header)) {
580 target.remove(i);
581 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700582 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700583 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700584 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700585 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700586 target.remove(i);
587 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700588 } else if (id == R.id.nfc_payment_settings) {
Martijn Coenen81ab8172013-09-30 12:07:02 -0700589 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
Martijn Coenen26515da2013-08-01 18:13:33 -0700590 target.remove(i);
Martijn Coenen81ab8172013-09-30 12:07:02 -0700591 } else {
592 // Only show if NFC is on and we have the HCE feature
593 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
594 if (!adapter.isEnabled() || !getPackageManager().hasSystemFeature(
595 PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
596 target.remove(i);
597 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700598 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700599 } else if (id == R.id.development_settings) {
600 if (!showDev) {
601 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700602 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400603 } else if (id == R.id.account_add) {
604 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
605 target.remove(i);
606 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700607 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700608
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900609 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700610 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700611 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700612 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700613 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700614
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700615 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900616 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800617 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700618 if (mFirstHeader == null &&
619 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
620 mFirstHeader = header;
621 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700622 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700623 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700624 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700625 }
626 }
627
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700628 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
629 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
630 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
631 for (String accountType : accountTypes) {
632 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700633 if (label == null) {
634 continue;
635 }
636
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700637 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
638 boolean skipToAccount = accounts.length == 1
639 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700640 Header accHeader = new Header();
641 accHeader.title = label;
642 if (accHeader.extras == null) {
643 accHeader.extras = new Bundle();
644 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700645 if (skipToAccount) {
646 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
647 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
648 accHeader.fragment = AccountSyncSettings.class.getName();
649 accHeader.fragmentArguments = new Bundle();
650 // Need this for the icon
651 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
652 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
653 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
654 accounts[0]);
655 } else {
656 accHeader.breadCrumbTitle = label;
657 accHeader.breadCrumbShortTitle = label;
658 accHeader.fragment = ManageAccountsSettings.class.getName();
659 accHeader.fragmentArguments = new Bundle();
660 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
661 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
662 accountType);
663 if (!isMultiPane()) {
664 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
665 label.toString());
666 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700667 }
668 accountHeaders.add(accHeader);
Amith Yamasani2972c012013-10-02 11:48:46 -0700669 mAuthenticatorHelper.preloadDrawableForType(this, accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700670 }
671
672 // Sort by label
673 Collections.sort(accountHeaders, new Comparator<Header>() {
674 @Override
675 public int compare(Header h1, Header h2) {
676 return h1.title.toString().compareTo(h2.title.toString());
677 }
678 });
679
680 for (Header header : accountHeaders) {
681 target.add(headerIndex++, header);
682 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700683 if (!mListeningToAccountUpdates) {
684 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
685 mListeningToAccountUpdates = true;
686 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700687 return headerIndex;
688 }
689
Christopher Tate8243c9a2013-09-19 14:59:17 -0700690 private boolean updateHomeSettingHeaders(Header header) {
Christopher Tatedc7be102013-10-08 11:30:19 -0700691 // Once we decide to show Home settings, keep showing it forever
692 SharedPreferences sp = getSharedPreferences(HomeSettings.HOME_PREFS, Context.MODE_PRIVATE);
693 if (sp.getBoolean(HomeSettings.HOME_PREFS_DO_SHOW, false)) {
694 return true;
695 }
696
Christopher Tatee238a472013-08-27 14:21:46 -0700697 try {
Jeff Sharkeyd572a032013-09-23 17:41:16 -0700698 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
699 getPackageManager().getHomeActivities(homeApps);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700700 if (homeApps.size() < 2) {
701 // When there's only one available home app, omit this settings
Christopher Tatee0d934f2013-10-01 12:32:27 -0700702 // category entirely at the top level UI. If the user just
703 // uninstalled the penultimate home app candidiate, we also
704 // now tell them about why they aren't seeing 'Home' in the list.
705 if (sShowNoHomeNotice) {
706 sShowNoHomeNotice = false;
707 NoHomeDialogFragment.show(this);
708 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700709 return false;
Christopher Tatee0d934f2013-10-01 12:32:27 -0700710 } else {
711 // Okay, we're allowing the Home settings category. Tell it, when
712 // invoked via this front door, that we'll need to be told about the
713 // case when the user uninstalls all but one home app.
714 if (header.fragmentArguments == null) {
715 header.fragmentArguments = new Bundle();
716 }
717 header.fragmentArguments.putBoolean(HomeSettings.HOME_SHOW_NOTICE, true);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700718 }
Christopher Tatee238a472013-08-27 14:21:46 -0700719 } catch (Exception e) {
720 // Can't look up the home activity; bail on configuring the icon
721 Log.w(LOG_TAG, "Problem looking up home activity!", e);
722 }
Christopher Tatedc7be102013-10-08 11:30:19 -0700723
724 sp.edit().putBoolean(HomeSettings.HOME_PREFS_DO_SHOW, true).apply();
Christopher Tate8243c9a2013-09-19 14:59:17 -0700725 return true;
Christopher Tatee238a472013-08-27 14:21:46 -0700726 }
727
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700728 private void getMetaData() {
729 try {
730 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
731 PackageManager.GET_META_DATA);
732 if (ai == null || ai.metaData == null) return;
733 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
734 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700735
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800736 // Check if it has a parent specified and create a Header object
737 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
738 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
739 if (parentFragmentClass != null) {
740 mParentHeader = new Header();
741 mParentHeader.fragment = parentFragmentClass;
742 if (parentHeaderTitleRes != 0) {
743 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
744 }
745 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700746 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700747 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700748 }
749 }
750
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800751 @Override
752 public boolean hasNextButton() {
753 return super.hasNextButton();
754 }
755
756 @Override
757 public Button getNextButton() {
758 return super.getNextButton();
759 }
760
Christopher Tatee0d934f2013-10-01 12:32:27 -0700761 public static class NoHomeDialogFragment extends DialogFragment {
762 public static void show(Activity parent) {
763 final NoHomeDialogFragment dialog = new NoHomeDialogFragment();
764 dialog.show(parent.getFragmentManager(), null);
765 }
766
767 @Override
768 public Dialog onCreateDialog(Bundle savedInstanceState) {
769 return new AlertDialog.Builder(getActivity())
770 .setMessage(R.string.only_one_home_message)
771 .setPositiveButton(android.R.string.ok, null)
772 .create();
773 }
774 }
775
Gilles Debunnee78c1872011-06-20 15:00:07 -0700776 private static class HeaderAdapter extends ArrayAdapter<Header> {
777 static final int HEADER_TYPE_CATEGORY = 0;
778 static final int HEADER_TYPE_NORMAL = 1;
779 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400780 static final int HEADER_TYPE_BUTTON = 3;
781 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700782
783 private final WifiEnabler mWifiEnabler;
784 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700785 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400786 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700787
788 private static class HeaderViewHolder {
789 ImageView icon;
790 TextView title;
791 TextView summary;
792 Switch switch_;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400793 ImageButton button_;
794 View divider_;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700795 }
796
797 private LayoutInflater mInflater;
798
799 static int getHeaderType(Header header) {
800 if (header.fragment == null && header.intent == null) {
801 return HEADER_TYPE_CATEGORY;
802 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
803 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400804 } else if (header.id == R.id.security_settings) {
805 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700806 } else {
807 return HEADER_TYPE_NORMAL;
808 }
809 }
810
811 @Override
812 public int getItemViewType(int position) {
813 Header header = getItem(position);
814 return getHeaderType(header);
815 }
816
817 @Override
818 public boolean areAllItemsEnabled() {
819 return false; // because of categories
820 }
821
822 @Override
823 public boolean isEnabled(int position) {
824 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
825 }
826
827 @Override
828 public int getViewTypeCount() {
829 return HEADER_TYPE_COUNT;
830 }
831
832 @Override
833 public boolean hasStableIds() {
834 return true;
835 }
836
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700837 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400838 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700839 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700840
841 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700842 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700843
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700844 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700845 // Switches inflated from their layouts. Must be done before adapter is set in super
846 mWifiEnabler = new WifiEnabler(context, new Switch(context));
847 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400848 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700849 }
850
851 @Override
852 public View getView(int position, View convertView, ViewGroup parent) {
853 HeaderViewHolder holder;
854 Header header = getItem(position);
855 int headerType = getHeaderType(header);
856 View view = null;
857
858 if (convertView == null) {
859 holder = new HeaderViewHolder();
860 switch (headerType) {
861 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700862 view = new TextView(getContext(), null,
863 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700864 holder.title = (TextView) view;
865 break;
866
867 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700868 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
869 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700870 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700871 holder.title = (TextView)
872 view.findViewById(com.android.internal.R.id.title);
873 holder.summary = (TextView)
874 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700875 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
876 break;
877
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400878 case HEADER_TYPE_BUTTON:
879 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
880 false);
881 holder.icon = (ImageView) view.findViewById(R.id.icon);
882 holder.title = (TextView)
883 view.findViewById(com.android.internal.R.id.title);
884 holder.summary = (TextView)
885 view.findViewById(com.android.internal.R.id.summary);
886 holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget);
887 holder.divider_ = view.findViewById(R.id.divider);
888 break;
889
Gilles Debunnee78c1872011-06-20 15:00:07 -0700890 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700891 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700892 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700893 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700894 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700895 holder.title = (TextView)
896 view.findViewById(com.android.internal.R.id.title);
897 holder.summary = (TextView)
898 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700899 break;
900 }
901 view.setTag(holder);
902 } else {
903 view = convertView;
904 holder = (HeaderViewHolder) view.getTag();
905 }
906
907 // All view fields must be updated every time, because the view may be recycled
908 switch (headerType) {
909 case HEADER_TYPE_CATEGORY:
910 holder.title.setText(header.getTitle(getContext().getResources()));
911 break;
912
913 case HEADER_TYPE_SWITCH:
914 // Would need a different treatment if the main menu had more switches
915 if (header.id == R.id.wifi_settings) {
916 mWifiEnabler.setSwitch(holder.switch_);
917 } else {
918 mBluetoothEnabler.setSwitch(holder.switch_);
919 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400920 updateCommonHeaderView(header, holder);
921 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700922
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400923 case HEADER_TYPE_BUTTON:
924 if (header.id == R.id.security_settings) {
925 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
926 if (hasCert) {
927 holder.button_.setVisibility(View.VISIBLE);
928 holder.divider_.setVisibility(View.VISIBLE);
929 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
930 if (isManaged) {
Maggie Benthall273155c2013-09-18 16:53:23 -0400931 holder.button_.setImageResource(R.drawable.ic_settings_about);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400932 } else {
933 holder.button_.setImageResource(
934 android.R.drawable.stat_notify_error);
935 }
936 holder.button_.setOnClickListener(new OnClickListener() {
937 @Override
938 public void onClick(View v) {
939 Intent intent = new Intent(
940 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
941 getContext().startActivity(intent);
942 }
943 });
944 } else {
945 holder.button_.setVisibility(View.GONE);
946 holder.divider_.setVisibility(View.GONE);
947 }
948 }
949 updateCommonHeaderView(header, holder);
950 break;
951
Gilles Debunnee78c1872011-06-20 15:00:07 -0700952 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400953 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700954 break;
955 }
956
957 return view;
958 }
959
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400960 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
961 if (header.extras != null
962 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
963 String accType = header.extras.getString(
964 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
965 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
966 setHeaderIcon(holder, icon);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400967 } else {
968 holder.icon.setImageResource(header.iconRes);
969 }
970 holder.title.setText(header.getTitle(getContext().getResources()));
971 CharSequence summary = header.getSummary(getContext().getResources());
972 if (!TextUtils.isEmpty(summary)) {
973 holder.summary.setVisibility(View.VISIBLE);
974 holder.summary.setText(summary);
975 } else {
976 holder.summary.setVisibility(View.GONE);
977 }
978 }
979
Christopher Tatee238a472013-08-27 14:21:46 -0700980 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
981 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
982 lp.width = getContext().getResources().getDimensionPixelSize(
983 R.dimen.header_icon_width);
984 lp.height = lp.width;
985 holder.icon.setLayoutParams(lp);
986 holder.icon.setImageDrawable(icon);
987 }
988
Gilles Debunnee78c1872011-06-20 15:00:07 -0700989 public void resume() {
990 mWifiEnabler.resume();
991 mBluetoothEnabler.resume();
992 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700993
Gilles Debunnee78c1872011-06-20 15:00:07 -0700994 public void pause() {
995 mWifiEnabler.pause();
996 mBluetoothEnabler.pause();
997 }
998 }
999
1000 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -07001001 public void onHeaderClick(Header header, int position) {
1002 boolean revert = false;
1003 if (header.id == R.id.account_add) {
1004 revert = true;
1005 }
1006
1007 super.onHeaderClick(header, position);
1008
1009 if (revert && mLastHeader != null) {
1010 highlightHeader((int) mLastHeader.id);
1011 } else {
1012 mLastHeader = header;
1013 }
1014 }
1015
1016 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -07001017 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
1018 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -08001019 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -07001020 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -08001021 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -07001022 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
1023 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -07001024 if (UserManager.get(this).isLinkedUser()) {
1025 titleRes = R.string.profile_info_settings_title;
1026 } else {
1027 titleRes = R.string.user_info_settings_title;
1028 }
Amith Yamasania4379d62011-07-22 10:34:58 -07001029 }
Jean Chalard7dabe452012-05-10 18:08:07 +09001030 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
1031 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -07001032 return true;
1033 }
1034
Maggie Benthall0c5a4012013-03-14 17:41:27 -04001035 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -07001036 public boolean shouldUpRecreateTask(Intent targetIntent) {
1037 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
1038 }
1039
Amith Yamasania4379d62011-07-22 10:34:58 -07001040 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -07001041 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -07001042 if (adapter == null) {
1043 super.setListAdapter(null);
1044 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -04001045 DevicePolicyManager dpm =
1046 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
1047 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -07001048 }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001049 }
1050
Amith Yamasani56821db2012-06-05 13:20:45 -07001051 @Override
1052 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -07001053 // TODO: watch for package upgrades to invalidate cache; see 7206643
1054 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -07001055 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
1056 invalidateHeaders();
1057 }
1058
Christopher Tatee0d934f2013-10-01 12:32:27 -07001059 public static void requestHomeNotice() {
1060 sShowNoHomeNotice = true;
1061 }
1062
Amith Yamasani5203bdf2010-11-04 09:59:44 -07001063 /*
1064 * Settings subclasses for launching independently.
1065 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001066 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1067 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1068 public static class TetherSettingsActivity extends Settings { /* empty */ }
1069 public static class VpnSettingsActivity extends Settings { /* empty */ }
1070 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1071 public static class StorageSettingsActivity extends Settings { /* empty */ }
1072 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001073 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001074 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001075 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001076 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001077 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001078 public static class LocalePickerActivity extends Settings { /* empty */ }
1079 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1080 public static class SoundSettingsActivity extends Settings { /* empty */ }
1081 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1082 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1083 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1084 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Dianne Hackborna522a8e2013-01-15 19:02:05 -08001085 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001086 public static class StorageUseActivity extends Settings { /* empty */ }
1087 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1088 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001089 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001090 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001091 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001092 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001093 public static class RunningServicesActivity extends Settings { /* empty */ }
1094 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1095 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1096 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1097 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1098 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1099 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1100 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001101 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001102 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001103 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001104 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001105 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001106 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001107 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001108 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001109 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001110 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001111 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001112 public static class PrintSettingsActivity extends Settings { /* empty */ }
Svetoslavd9f156d2013-10-09 21:59:04 -07001113 public static class PrintJobSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001114}