blob: 87feab79dc677c2289074010196e438f02191a65 [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;
Svetoslav2d531652013-09-03 21:32:40 -070084import com.android.settings.print.PrintServiceSettingsFragment;
85import com.android.settings.print.PrintSettingsFragment;
Amith Yamasania677ee22013-07-26 13:38:41 -070086import com.android.settings.tts.TextToSpeechSettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070087import com.android.settings.users.UserSettings;
88import com.android.settings.vpn2.VpnSettings;
Jeff Sharkey0c3634c2013-02-20 12:35:16 -080089import com.android.settings.wfd.WifiDisplaySettings;
Amith Yamasania677ee22013-07-26 13:38:41 -070090import com.android.settings.wifi.AdvancedWifiSettings;
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080091import com.android.settings.wifi.WifiEnabler;
92import com.android.settings.wifi.WifiSettings;
93import com.android.settings.wifi.p2p.WifiP2pSettings;
94
Gilles Debunnee78c1872011-06-20 15:00:07 -070095import java.util.ArrayList;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070096import java.util.Collections;
97import java.util.Comparator;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070098import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070099import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -0700100
101/**
102 * Top-level settings activity to handle single pane and double pane UI layout.
103 */
Amith Yamasani56821db2012-06-05 13:20:45 -0700104public class Settings extends PreferenceActivity
105 implements ButtonBarHandler, OnAccountsUpdateListener {
Amith Yamasanid7993472010-08-18 13:59:28 -0700106
Gilles Debunnee78c1872011-06-20 15:00:07 -0700107 private static final String LOG_TAG = "Settings";
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700108
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700109 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700110 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700111 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -0700112 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800113 private static final String META_DATA_KEY_PARENT_TITLE =
114 "com.android.settings.PARENT_FRAGMENT_TITLE";
115 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
116 "com.android.settings.PARENT_FRAGMENT_CLASS";
117
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800118 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700119
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800120 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
121 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700122
Christopher Tatee0d934f2013-10-01 12:32:27 -0700123 static final int DIALOG_ONLY_ONE_HOME = 1;
124
125 private static boolean sShowNoHomeNotice = false;
126
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700127 private String mFragmentClass;
128 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -0800129 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800130 private Header mCurrentHeader;
131 private Header mParentHeader;
132 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700133
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700134 // Show only these settings for restricted users
135 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700136 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700137 R.id.wifi_settings,
138 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700139 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700140 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700141 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700142 R.id.sound_settings,
143 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700144 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700145 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700146 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700147 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700148 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700149 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700150 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700151 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700152 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700153 R.id.account_add,
154 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700155 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700156 R.id.about_settings,
Svetoslav Ganovd4c7b492013-06-11 21:15:11 -0700157 R.id.accessibility_settings,
Martijn Coenen26515da2013-08-01 18:13:33 -0700158 R.id.print_settings,
Christopher Tatee238a472013-08-27 14:21:46 -0700159 R.id.nfc_payment_settings,
160 R.id.home_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700161 };
162
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700163 private SharedPreferences mDevelopmentPreferences;
164 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
165
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700166 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700167
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700168 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
169
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700170 private AuthenticatorHelper mAuthenticatorHelper;
171 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700172 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700173
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900174 private boolean mBatteryPresent = true;
175 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
176
177 @Override
178 public void onReceive(Context context, Intent intent) {
179 String action = intent.getAction();
180 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
181 boolean batteryPresent = Utils.isBatteryPresent(intent);
182
183 if (mBatteryPresent != batteryPresent) {
184 mBatteryPresent = batteryPresent;
185 invalidateHeaders();
186 }
187 }
188 }
189 };
190
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700191 @Override
192 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800193 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
194 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700195 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700196
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700197 mAuthenticatorHelper = new AuthenticatorHelper();
198 mAuthenticatorHelper.updateAuthDescriptions(this);
199 mAuthenticatorHelper.onAccountsUpdated(this, null);
200
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700201 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
202 Context.MODE_PRIVATE);
203
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700204 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800205 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700206 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800207 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700208
Gilles Debunne3661b622011-06-27 11:19:16 -0700209 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700210 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800211 // Force the title so that it doesn't get overridden by a direct launch of
212 // a specific settings screen.
213 setTitle(R.string.settings_label);
214 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800215
216 // Retrieve any saved state
217 if (savedInstanceState != null) {
218 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
219 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
220 }
221
222 // If the current header was saved, switch to it
223 if (savedInstanceState != null && mCurrentHeader != null) {
224 //switchToHeaderLocal(mCurrentHeader);
225 showBreadCrumbs(mCurrentHeader.title, null);
226 }
227
228 if (mParentHeader != null) {
229 setParentTitle(mParentHeader.title, null, new OnClickListener() {
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400230 @Override
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800231 public void onClick(View v) {
232 switchToParent(mParentHeader.fragment);
233 }
234 });
235 }
Gilles Debunnedc7101f2011-06-27 12:00:49 -0700236
Amith Yamasani3d384f42012-05-11 15:22:04 -0700237 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
238 if (onIsMultiPane()) {
239 getActionBar().setDisplayHomeAsUpEnabled(false);
240 getActionBar().setHomeButtonEnabled(false);
241 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800242 }
243
244 @Override
245 protected void onSaveInstanceState(Bundle outState) {
246 super.onSaveInstanceState(outState);
247
248 // Save the current fragment, if it is the same as originally launched
249 if (mCurrentHeader != null) {
250 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
251 }
252 if (mParentHeader != null) {
253 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
254 }
255 }
256
Gilles Debunnee78c1872011-06-20 15:00:07 -0700257 @Override
258 public void onResume() {
259 super.onResume();
260
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700261 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
262 @Override
263 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
264 invalidateHeaders();
265 }
266 };
267 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
268 mDevelopmentPreferencesListener);
269
Gilles Debunnee78c1872011-06-20 15:00:07 -0700270 ListAdapter listAdapter = getListAdapter();
271 if (listAdapter instanceof HeaderAdapter) {
272 ((HeaderAdapter) listAdapter).resume();
273 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700274 invalidateHeaders();
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900275
276 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700277 }
278
279 @Override
280 public void onPause() {
281 super.onPause();
282
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900283 unregisterReceiver(mBatteryInfoReceiver);
284
Gilles Debunnee78c1872011-06-20 15:00:07 -0700285 ListAdapter listAdapter = getListAdapter();
286 if (listAdapter instanceof HeaderAdapter) {
287 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700288 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700289
290 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
291 mDevelopmentPreferencesListener);
292 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700293 }
294
295 @Override
296 public void onDestroy() {
297 super.onDestroy();
298 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700299 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700300 }
301 }
302
Amith Yamasani56f51a82013-08-05 10:07:23 -0700303 @Override
304 public boolean onIsMultiPane() {
305 return false;
306 }
307
Amith Yamasania677ee22013-07-26 13:38:41 -0700308 private static final String[] ENTRY_FRAGMENTS = {
309 WirelessSettings.class.getName(),
310 WifiSettings.class.getName(),
311 AdvancedWifiSettings.class.getName(),
312 BluetoothSettings.class.getName(),
313 TetherSettings.class.getName(),
314 WifiP2pSettings.class.getName(),
315 VpnSettings.class.getName(),
316 DateTimeSettings.class.getName(),
317 LocalePicker.class.getName(),
318 InputMethodAndLanguageSettings.class.getName(),
319 SpellCheckersSettings.class.getName(),
320 UserDictionaryList.class.getName(),
321 UserDictionarySettings.class.getName(),
322 SoundSettings.class.getName(),
323 DisplaySettings.class.getName(),
324 DeviceInfoSettings.class.getName(),
325 ManageApplications.class.getName(),
Dianne Hackbornc6d658e2013-08-08 12:57:53 -0700326 ProcessStatsUi.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700327 NotificationStation.class.getName(),
328 AppOpsSummary.class.getName(),
329 LocationSettings.class.getName(),
330 SecuritySettings.class.getName(),
331 PrivacySettings.class.getName(),
332 DeviceAdminSettings.class.getName(),
333 AccessibilitySettings.class.getName(),
Alan Viverette9b625f02013-09-11 13:03:14 -0700334 ToggleCaptioningPreferenceFragment.class.getName(),
Amith Yamasania677ee22013-07-26 13:38:41 -0700335 TextToSpeechSettings.class.getName(),
336 Memory.class.getName(),
337 DevelopmentSettings.class.getName(),
338 UsbSettings.class.getName(),
339 AndroidBeam.class.getName(),
340 WifiDisplaySettings.class.getName(),
341 PowerUsageSummary.class.getName(),
342 AccountSyncSettings.class.getName(),
343 CryptKeeperSettings.class.getName(),
344 DataUsageSummary.class.getName(),
345 DreamSettings.class.getName(),
346 UserSettings.class.getName(),
347 NotificationAccessSettings.class.getName(),
Amith Yamasaniee226f92013-08-05 11:02:16 -0700348 ManageAccountsSettings.class.getName(),
Svetoslav2d531652013-09-03 21:32:40 -0700349 PrintSettingsFragment.class.getName(),
Martijn Coenen53083ab2013-08-09 13:37:38 -0700350 TrustedCredentialsSettings.class.getName(),
Amith Yamasani3a14ae22013-08-30 15:43:44 -0700351 PaymentSettings.class.getName(),
352 KeyboardLayoutPickerFragment.class.getName()
Amith Yamasania677ee22013-07-26 13:38:41 -0700353 };
354
355 @Override
356 protected boolean isValidFragment(String fragmentName) {
357 // Almost all fragments are wrapped in this,
358 // except for a few that have their own activities.
359 for (int i = 0; i < ENTRY_FRAGMENTS.length; i++) {
360 if (ENTRY_FRAGMENTS[i].equals(fragmentName)) return true;
361 }
362 return false;
363 }
364
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800365 private void switchToHeaderLocal(Header header) {
366 mInLocalHeaderSwitch = true;
367 switchToHeader(header);
368 mInLocalHeaderSwitch = false;
369 }
370
371 @Override
372 public void switchToHeader(Header header) {
373 if (!mInLocalHeaderSwitch) {
374 mCurrentHeader = null;
375 mParentHeader = null;
376 }
377 super.switchToHeader(header);
378 }
379
380 /**
381 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800382 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800383 */
384 private void switchToParent(String className) {
385 final ComponentName cn = new ComponentName(this, className);
386 try {
387 final PackageManager pm = getPackageManager();
388 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
389
390 if (parentInfo != null && parentInfo.metaData != null) {
391 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
392 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
393 Header parentHeader = new Header();
394 parentHeader.fragment = fragmentClass;
395 parentHeader.title = fragmentTitle;
396 mCurrentHeader = parentHeader;
397
398 switchToHeaderLocal(parentHeader);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700399 highlightHeader(mTopLevelHeaderId);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800400
401 mParentHeader = new Header();
402 mParentHeader.fragment
403 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
404 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
405 }
406 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700407 Log.w(LOG_TAG, "Could not find parent activity : " + className);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800408 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700409 }
410
Amith Yamasani3965ae62010-11-15 14:45:19 -0800411 @Override
412 public void onNewIntent(Intent intent) {
413 super.onNewIntent(intent);
414
415 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700416 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
417 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
418 switchToHeaderLocal(mFirstHeader);
419 }
420 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800421 }
422 }
423
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700424 private void highlightHeader(int id) {
425 if (id != 0) {
426 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700427 if (index != null) {
428 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700429 if (isMultiPane()) {
430 getListView().smoothScrollToPosition(index);
431 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700432 }
433 }
434 }
435
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700436 @Override
437 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700438 Intent superIntent = super.getIntent();
439 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700440 // This is called from super.onCreate, isMultiPane() is not yet reliable
441 // Do not use onIsHidingHeaders either, which relies itself on this method
442 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700443 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700444 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700445 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700446 if (args != null) {
447 args = new Bundle(args);
448 } else {
449 args = new Bundle();
450 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700451 args.putParcelable("intent", superIntent);
452 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700453 return modIntent;
454 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700455 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700456 }
457
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700458 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700459 * Checks if the component name in the intent is different from the Settings class and
460 * returns the class name to load as a fragment.
461 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700462 protected String getStartingFragmentClass(Intent intent) {
463 if (mFragmentClass != null) return mFragmentClass;
464
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700465 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700466 if (intentClass.equals(getClass().getName())) return null;
467
Dianne Hackbornee293792010-11-01 12:32:33 -0700468 if ("com.android.settings.ManageApplications".equals(intentClass)
469 || "com.android.settings.RunningServices".equals(intentClass)
470 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700471 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700472 intentClass = com.android.settings.applications.ManageApplications.class.getName();
473 }
474
Amith Yamasani379d9b02010-09-27 12:03:59 -0700475 return intentClass;
476 }
477
478 /**
479 * Override initial header when an activity-alias is causing Settings to be launched
480 * for a specific fragment encoded in the android:name parameter.
481 */
482 @Override
483 public Header onGetInitialHeader() {
484 String fragmentClass = getStartingFragmentClass(super.getIntent());
485 if (fragmentClass != null) {
486 Header header = new Header();
487 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800488 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700489 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800490 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700491 return header;
492 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700493
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700494 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700495 }
496
Dianne Hackbornb7258182011-03-15 16:23:55 -0700497 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700498 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
499 int titleRes, int shortTitleRes) {
500 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
501 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700502
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800503 // Some fragments want split ActionBar; these should stay in sync with
504 // uiOptions for fragments also defined as activities in manifest.
505 if (WifiSettings.class.getName().equals(fragmentName) ||
506 WifiP2pSettings.class.getName().equals(fragmentName) ||
Jeff Sharkey0c3634c2013-02-20 12:35:16 -0800507 WifiDisplaySettings.class.getName().equals(fragmentName) ||
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800508 BluetoothSettings.class.getName().equals(fragmentName) ||
509 DreamSettings.class.getName().equals(fragmentName) ||
Lifu Tangd5fbbc42013-08-01 17:23:10 -0700510 LocationSettings.class.getName().equals(fragmentName) ||
Svetoslav2d531652013-09-03 21:32:40 -0700511 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName) ||
512 PrintSettingsFragment.class.getName().equals(fragmentName) ||
513 PrintServiceSettingsFragment.class.getName().equals(fragmentName)) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800514 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700515 }
516
Dianne Hackbornb7258182011-03-15 16:23:55 -0700517 intent.setClass(this, SubSettings.class);
518 return intent;
519 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700520
Amith Yamasani379d9b02010-09-27 12:03:59 -0700521 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700522 * Populate the activity with the top-level headers.
523 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700524 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700525 public void onBuildHeaders(List<Header> headers) {
526 loadHeadersFromResource(R.xml.settings_headers, headers);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700527 updateHeaderList(headers);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700528 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700529
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700530 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700531 final boolean showDev = mDevelopmentPreferences.getBoolean(
532 DevelopmentSettings.PREF_SHOW,
533 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700534 int i = 0;
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400535
536 final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700537 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700538 while (i < target.size()) {
539 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700540 // Ids are integers, so downcasting
541 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400542 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700543 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700544 } else if (id == R.id.wifi_settings) {
545 // Remove WiFi Settings if WiFi service is not available.
546 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700547 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700548 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700549 } else if (id == R.id.bluetooth_settings) {
550 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700551 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700552 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700553 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700554 } else if (id == R.id.data_usage_settings) {
555 // Remove data usage when kernel module not enabled
556 final INetworkManagementService netManager = INetworkManagementService.Stub
557 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
558 try {
559 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700560 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700561 }
562 } catch (RemoteException e) {
563 // ignored
564 }
Jaewan Kima3fe77b2013-06-04 21:17:40 +0900565 } else if (id == R.id.battery_settings) {
566 // Remove battery settings when battery is not available. (e.g. TV)
567
568 if (!mBatteryPresent) {
569 target.remove(i);
570 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700571 } else if (id == R.id.account_settings) {
572 int headerIndex = i + 1;
573 i = insertAccountsHeaders(target, headerIndex);
Christopher Tatee238a472013-08-27 14:21:46 -0700574 } else if (id == R.id.home_settings) {
Christopher Tate8243c9a2013-09-19 14:59:17 -0700575 if (!updateHomeSettingHeaders(header)) {
576 target.remove(i);
577 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700578 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700579 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700580 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700581 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700582 target.remove(i);
583 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700584 } else if (id == R.id.nfc_payment_settings) {
Martijn Coenen81ab8172013-09-30 12:07:02 -0700585 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
Martijn Coenen26515da2013-08-01 18:13:33 -0700586 target.remove(i);
Martijn Coenen81ab8172013-09-30 12:07:02 -0700587 } else {
588 // Only show if NFC is on and we have the HCE feature
589 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
590 if (!adapter.isEnabled() || !getPackageManager().hasSystemFeature(
591 PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
592 target.remove(i);
593 }
Martijn Coenen26515da2013-08-01 18:13:33 -0700594 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700595 } else if (id == R.id.development_settings) {
596 if (!showDev) {
597 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700598 }
Maggie Benthall0c5a4012013-03-14 17:41:27 -0400599 } else if (id == R.id.account_add) {
600 if (um.hasUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
601 target.remove(i);
602 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700603 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700604
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900605 if (i < target.size() && target.get(i) == header
Amith Yamasanib99f8642012-10-10 21:41:12 -0700606 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700607 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700608 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700609 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700610
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700611 // Increment if the current one wasn't removed by the Utils code.
Jaewan Kimbb0e6212013-02-04 15:36:17 +0900612 if (i < target.size() && target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800613 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700614 if (mFirstHeader == null &&
615 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
616 mFirstHeader = header;
617 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700618 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700619 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700620 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700621 }
622 }
623
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700624 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
625 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
626 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
627 for (String accountType : accountTypes) {
628 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700629 if (label == null) {
630 continue;
631 }
632
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700633 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
634 boolean skipToAccount = accounts.length == 1
635 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700636 Header accHeader = new Header();
637 accHeader.title = label;
638 if (accHeader.extras == null) {
639 accHeader.extras = new Bundle();
640 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700641 if (skipToAccount) {
642 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
643 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
644 accHeader.fragment = AccountSyncSettings.class.getName();
645 accHeader.fragmentArguments = new Bundle();
646 // Need this for the icon
647 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
648 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
649 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
650 accounts[0]);
651 } else {
652 accHeader.breadCrumbTitle = label;
653 accHeader.breadCrumbShortTitle = label;
654 accHeader.fragment = ManageAccountsSettings.class.getName();
655 accHeader.fragmentArguments = new Bundle();
656 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
657 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
658 accountType);
659 if (!isMultiPane()) {
660 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
661 label.toString());
662 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700663 }
664 accountHeaders.add(accHeader);
665 }
666
667 // Sort by label
668 Collections.sort(accountHeaders, new Comparator<Header>() {
669 @Override
670 public int compare(Header h1, Header h2) {
671 return h1.title.toString().compareTo(h2.title.toString());
672 }
673 });
674
675 for (Header header : accountHeaders) {
676 target.add(headerIndex++, header);
677 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700678 if (!mListeningToAccountUpdates) {
679 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
680 mListeningToAccountUpdates = true;
681 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700682 return headerIndex;
683 }
684
Christopher Tate8243c9a2013-09-19 14:59:17 -0700685 private boolean updateHomeSettingHeaders(Header header) {
Christopher Tatee238a472013-08-27 14:21:46 -0700686 try {
Jeff Sharkeyd572a032013-09-23 17:41:16 -0700687 final ArrayList<ResolveInfo> homeApps = new ArrayList<ResolveInfo>();
688 getPackageManager().getHomeActivities(homeApps);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700689 if (homeApps.size() < 2) {
690 // When there's only one available home app, omit this settings
Christopher Tatee0d934f2013-10-01 12:32:27 -0700691 // category entirely at the top level UI. If the user just
692 // uninstalled the penultimate home app candidiate, we also
693 // now tell them about why they aren't seeing 'Home' in the list.
694 if (sShowNoHomeNotice) {
695 sShowNoHomeNotice = false;
696 NoHomeDialogFragment.show(this);
697 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700698 return false;
Christopher Tatee0d934f2013-10-01 12:32:27 -0700699 } else {
700 // Okay, we're allowing the Home settings category. Tell it, when
701 // invoked via this front door, that we'll need to be told about the
702 // case when the user uninstalls all but one home app.
703 if (header.fragmentArguments == null) {
704 header.fragmentArguments = new Bundle();
705 }
706 header.fragmentArguments.putBoolean(HomeSettings.HOME_SHOW_NOTICE, true);
Christopher Tate8243c9a2013-09-19 14:59:17 -0700707 }
Christopher Tatee238a472013-08-27 14:21:46 -0700708 } catch (Exception e) {
709 // Can't look up the home activity; bail on configuring the icon
710 Log.w(LOG_TAG, "Problem looking up home activity!", e);
711 }
Christopher Tate8243c9a2013-09-19 14:59:17 -0700712 return true;
Christopher Tatee238a472013-08-27 14:21:46 -0700713 }
714
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700715 private void getMetaData() {
716 try {
717 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
718 PackageManager.GET_META_DATA);
719 if (ai == null || ai.metaData == null) return;
720 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
721 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700722
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800723 // Check if it has a parent specified and create a Header object
724 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
725 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
726 if (parentFragmentClass != null) {
727 mParentHeader = new Header();
728 mParentHeader.fragment = parentFragmentClass;
729 if (parentHeaderTitleRes != 0) {
730 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
731 }
732 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700733 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700734 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700735 }
736 }
737
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800738 @Override
739 public boolean hasNextButton() {
740 return super.hasNextButton();
741 }
742
743 @Override
744 public Button getNextButton() {
745 return super.getNextButton();
746 }
747
Christopher Tatee0d934f2013-10-01 12:32:27 -0700748 public static class NoHomeDialogFragment extends DialogFragment {
749 public static void show(Activity parent) {
750 final NoHomeDialogFragment dialog = new NoHomeDialogFragment();
751 dialog.show(parent.getFragmentManager(), null);
752 }
753
754 @Override
755 public Dialog onCreateDialog(Bundle savedInstanceState) {
756 return new AlertDialog.Builder(getActivity())
757 .setMessage(R.string.only_one_home_message)
758 .setPositiveButton(android.R.string.ok, null)
759 .create();
760 }
761 }
762
Gilles Debunnee78c1872011-06-20 15:00:07 -0700763 private static class HeaderAdapter extends ArrayAdapter<Header> {
764 static final int HEADER_TYPE_CATEGORY = 0;
765 static final int HEADER_TYPE_NORMAL = 1;
766 static final int HEADER_TYPE_SWITCH = 2;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400767 static final int HEADER_TYPE_BUTTON = 3;
768 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_BUTTON + 1;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700769
770 private final WifiEnabler mWifiEnabler;
771 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700772 private AuthenticatorHelper mAuthHelper;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400773 private DevicePolicyManager mDevicePolicyManager;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700774
775 private static class HeaderViewHolder {
776 ImageView icon;
777 TextView title;
778 TextView summary;
779 Switch switch_;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400780 ImageButton button_;
781 View divider_;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700782 }
783
784 private LayoutInflater mInflater;
785
786 static int getHeaderType(Header header) {
787 if (header.fragment == null && header.intent == null) {
788 return HEADER_TYPE_CATEGORY;
789 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
790 return HEADER_TYPE_SWITCH;
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400791 } else if (header.id == R.id.security_settings) {
792 return HEADER_TYPE_BUTTON;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700793 } else {
794 return HEADER_TYPE_NORMAL;
795 }
796 }
797
798 @Override
799 public int getItemViewType(int position) {
800 Header header = getItem(position);
801 return getHeaderType(header);
802 }
803
804 @Override
805 public boolean areAllItemsEnabled() {
806 return false; // because of categories
807 }
808
809 @Override
810 public boolean isEnabled(int position) {
811 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
812 }
813
814 @Override
815 public int getViewTypeCount() {
816 return HEADER_TYPE_COUNT;
817 }
818
819 @Override
820 public boolean hasStableIds() {
821 return true;
822 }
823
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700824 public HeaderAdapter(Context context, List<Header> objects,
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400825 AuthenticatorHelper authenticatorHelper, DevicePolicyManager dpm) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700826 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700827
828 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700829 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700830
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700831 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700832 // Switches inflated from their layouts. Must be done before adapter is set in super
833 mWifiEnabler = new WifiEnabler(context, new Switch(context));
834 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400835 mDevicePolicyManager = dpm;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700836 }
837
838 @Override
839 public View getView(int position, View convertView, ViewGroup parent) {
840 HeaderViewHolder holder;
841 Header header = getItem(position);
842 int headerType = getHeaderType(header);
843 View view = null;
844
845 if (convertView == null) {
846 holder = new HeaderViewHolder();
847 switch (headerType) {
848 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700849 view = new TextView(getContext(), null,
850 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700851 holder.title = (TextView) view;
852 break;
853
854 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700855 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
856 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700857 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700858 holder.title = (TextView)
859 view.findViewById(com.android.internal.R.id.title);
860 holder.summary = (TextView)
861 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700862 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
863 break;
864
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400865 case HEADER_TYPE_BUTTON:
866 view = mInflater.inflate(R.layout.preference_header_button_item, parent,
867 false);
868 holder.icon = (ImageView) view.findViewById(R.id.icon);
869 holder.title = (TextView)
870 view.findViewById(com.android.internal.R.id.title);
871 holder.summary = (TextView)
872 view.findViewById(com.android.internal.R.id.summary);
873 holder.button_ = (ImageButton) view.findViewById(R.id.buttonWidget);
874 holder.divider_ = view.findViewById(R.id.divider);
875 break;
876
Gilles Debunnee78c1872011-06-20 15:00:07 -0700877 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700878 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700879 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700880 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700881 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700882 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);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700886 break;
887 }
888 view.setTag(holder);
889 } else {
890 view = convertView;
891 holder = (HeaderViewHolder) view.getTag();
892 }
893
894 // All view fields must be updated every time, because the view may be recycled
895 switch (headerType) {
896 case HEADER_TYPE_CATEGORY:
897 holder.title.setText(header.getTitle(getContext().getResources()));
898 break;
899
900 case HEADER_TYPE_SWITCH:
901 // Would need a different treatment if the main menu had more switches
902 if (header.id == R.id.wifi_settings) {
903 mWifiEnabler.setSwitch(holder.switch_);
904 } else {
905 mBluetoothEnabler.setSwitch(holder.switch_);
906 }
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400907 updateCommonHeaderView(header, holder);
908 break;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700909
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400910 case HEADER_TYPE_BUTTON:
911 if (header.id == R.id.security_settings) {
912 boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
913 if (hasCert) {
914 holder.button_.setVisibility(View.VISIBLE);
915 holder.divider_.setVisibility(View.VISIBLE);
916 boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
917 if (isManaged) {
Maggie Benthall273155c2013-09-18 16:53:23 -0400918 holder.button_.setImageResource(R.drawable.ic_settings_about);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400919 } else {
920 holder.button_.setImageResource(
921 android.R.drawable.stat_notify_error);
922 }
923 holder.button_.setOnClickListener(new OnClickListener() {
924 @Override
925 public void onClick(View v) {
926 Intent intent = new Intent(
927 android.provider.Settings.ACTION_MONITORING_CERT_INFO);
928 getContext().startActivity(intent);
929 }
930 });
931 } else {
932 holder.button_.setVisibility(View.GONE);
933 holder.divider_.setVisibility(View.GONE);
934 }
935 }
936 updateCommonHeaderView(header, holder);
937 break;
938
Gilles Debunnee78c1872011-06-20 15:00:07 -0700939 case HEADER_TYPE_NORMAL:
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400940 updateCommonHeaderView(header, holder);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700941 break;
942 }
943
944 return view;
945 }
946
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400947 private void updateCommonHeaderView(Header header, HeaderViewHolder holder) {
948 if (header.extras != null
949 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
950 String accType = header.extras.getString(
951 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
952 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
953 setHeaderIcon(holder, icon);
Maggie Benthall9d6c40e2013-09-05 15:33:58 -0400954 } else {
955 holder.icon.setImageResource(header.iconRes);
956 }
957 holder.title.setText(header.getTitle(getContext().getResources()));
958 CharSequence summary = header.getSummary(getContext().getResources());
959 if (!TextUtils.isEmpty(summary)) {
960 holder.summary.setVisibility(View.VISIBLE);
961 holder.summary.setText(summary);
962 } else {
963 holder.summary.setVisibility(View.GONE);
964 }
965 }
966
Christopher Tatee238a472013-08-27 14:21:46 -0700967 private void setHeaderIcon(HeaderViewHolder holder, Drawable icon) {
968 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
969 lp.width = getContext().getResources().getDimensionPixelSize(
970 R.dimen.header_icon_width);
971 lp.height = lp.width;
972 holder.icon.setLayoutParams(lp);
973 holder.icon.setImageDrawable(icon);
974 }
975
Gilles Debunnee78c1872011-06-20 15:00:07 -0700976 public void resume() {
977 mWifiEnabler.resume();
978 mBluetoothEnabler.resume();
979 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700980
Gilles Debunnee78c1872011-06-20 15:00:07 -0700981 public void pause() {
982 mWifiEnabler.pause();
983 mBluetoothEnabler.pause();
984 }
985 }
986
987 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700988 public void onHeaderClick(Header header, int position) {
989 boolean revert = false;
990 if (header.id == R.id.account_add) {
991 revert = true;
992 }
993
994 super.onHeaderClick(header, position);
995
996 if (revert && mLastHeader != null) {
997 highlightHeader((int) mLastHeader.id);
998 } else {
999 mLastHeader = header;
1000 }
1001 }
1002
1003 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -07001004 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
1005 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -08001006 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -07001007 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -08001008 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -07001009 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
1010 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
Amith Yamasanib0171712013-04-28 22:13:22 -07001011 if (UserManager.get(this).isLinkedUser()) {
1012 titleRes = R.string.profile_info_settings_title;
1013 } else {
1014 titleRes = R.string.user_info_settings_title;
1015 }
Amith Yamasania4379d62011-07-22 10:34:58 -07001016 }
Jean Chalard7dabe452012-05-10 18:08:07 +09001017 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
1018 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -07001019 return true;
1020 }
1021
Maggie Benthall0c5a4012013-03-14 17:41:27 -04001022 @Override
Amith Yamasani3d384f42012-05-11 15:22:04 -07001023 public boolean shouldUpRecreateTask(Intent targetIntent) {
1024 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
1025 }
1026
Amith Yamasania4379d62011-07-22 10:34:58 -07001027 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -07001028 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -07001029 if (adapter == null) {
1030 super.setListAdapter(null);
1031 } else {
Maggie Benthall9d6c40e2013-09-05 15:33:58 -04001032 DevicePolicyManager dpm =
1033 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
1034 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper, dpm));
Gilles Debunnee78c1872011-06-20 15:00:07 -07001035 }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001036 }
1037
Amith Yamasani56821db2012-06-05 13:20:45 -07001038 @Override
1039 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -07001040 // TODO: watch for package upgrades to invalidate cache; see 7206643
1041 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -07001042 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
1043 invalidateHeaders();
1044 }
1045
Christopher Tatee0d934f2013-10-01 12:32:27 -07001046 public static void requestHomeNotice() {
1047 sShowNoHomeNotice = true;
1048 }
1049
Amith Yamasani5203bdf2010-11-04 09:59:44 -07001050 /*
1051 * Settings subclasses for launching independently.
1052 */
Gilles Debunnee78c1872011-06-20 15:00:07 -07001053 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
1054 public static class WirelessSettingsActivity extends Settings { /* empty */ }
1055 public static class TetherSettingsActivity extends Settings { /* empty */ }
1056 public static class VpnSettingsActivity extends Settings { /* empty */ }
1057 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
1058 public static class StorageSettingsActivity extends Settings { /* empty */ }
1059 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -07001060 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001061 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -07001062 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001063 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +09001064 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001065 public static class LocalePickerActivity extends Settings { /* empty */ }
1066 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
1067 public static class SoundSettingsActivity extends Settings { /* empty */ }
1068 public static class DisplaySettingsActivity extends Settings { /* empty */ }
1069 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
1070 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
1071 public static class ManageApplicationsActivity extends Settings { /* empty */ }
Dianne Hackborna522a8e2013-01-15 19:02:05 -08001072 public static class AppOpsSummaryActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001073 public static class StorageUseActivity extends Settings { /* empty */ }
1074 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
1075 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
Alan Viverette9b625f02013-09-11 13:03:14 -07001076 public static class CaptioningSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001077 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -07001078 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001079 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -07001080 public static class RunningServicesActivity extends Settings { /* empty */ }
1081 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
1082 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
1083 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
1084 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
1085 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
1086 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
1087 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001088 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -07001089 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -05001090 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -07001091 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -05001092 public static class DreamSettingsActivity extends Settings { /* empty */ }
Daniel Sandler328e2d22013-01-17 13:14:02 -05001093 public static class NotificationStationActivity extends Settings { /* empty */ }
Amith Yamasani233592b2013-03-01 17:05:23 -08001094 public static class UserSettingsActivity extends Settings { /* empty */ }
Daniel Sandler79b9bfe2013-04-04 14:30:04 -04001095 public static class NotificationAccessSettingsActivity extends Settings { /* empty */ }
Amith Yamasania677ee22013-07-26 13:38:41 -07001096 public static class UsbSettingsActivity extends Settings { /* empty */ }
Geoffrey Borggaardfc6bc202013-08-09 11:44:42 -04001097 public static class TrustedCredentialsSettingsActivity extends Settings { /* empty */ }
Martijn Coenen53083ab2013-08-09 13:37:38 -07001098 public static class PaymentSettingsActivity extends Settings { /* empty */ }
Svetoslav Ganov74648ac2013-09-04 23:52:28 -07001099 public static class PrintSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -08001100}