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