blob: f850f3910f3e0b99c852f56a8a262da2b3116368 [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;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080022import android.content.ComponentName;
Gilles Debunnee78c1872011-06-20 15:00:07 -070023import android.content.Context;
Amith Yamasani379d9b02010-09-27 12:03:59 -070024import android.content.Intent;
Dianne Hackborncaefa9b2012-10-10 15:05:42 -070025import android.content.SharedPreferences;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070026import android.content.pm.ActivityInfo;
27import android.content.pm.PackageManager;
28import android.content.pm.PackageManager.NameNotFoundException;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070029import android.graphics.drawable.Drawable;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070030import android.os.Bundle;
Jeff Sharkey34e964d2012-04-21 15:41:48 -070031import android.os.INetworkManagementService;
32import android.os.RemoteException;
33import android.os.ServiceManager;
Dianne Hackbornbb06a422012-08-16 11:01:57 -070034import android.os.UserHandle;
Jeff Sharkey44202462012-09-19 13:13:45 -070035import android.os.UserManager;
Amith Yamasania4379d62011-07-22 10:34:58 -070036import android.preference.Preference;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070037import android.preference.PreferenceActivity;
Amith Yamasania4379d62011-07-22 10:34:58 -070038import android.preference.PreferenceFragment;
Gilles Debunnee78c1872011-06-20 15:00:07 -070039import android.text.TextUtils;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080040import android.util.Log;
Gilles Debunnee78c1872011-06-20 15:00:07 -070041import android.view.LayoutInflater;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080042import android.view.View;
43import android.view.View.OnClickListener;
Gilles Debunnee78c1872011-06-20 15:00:07 -070044import android.view.ViewGroup;
45import android.widget.ArrayAdapter;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080046import android.widget.Button;
Gilles Debunnee78c1872011-06-20 15:00:07 -070047import android.widget.ImageView;
48import android.widget.ListAdapter;
49import android.widget.Switch;
50import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080051
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080052import com.android.internal.util.ArrayUtils;
53import com.android.settings.AccessibilitySettings.ToggleAccessibilityServicePreferenceFragment;
54import com.android.settings.accounts.AccountSyncSettings;
55import com.android.settings.accounts.AuthenticatorHelper;
56import com.android.settings.accounts.ManageAccountsSettings;
57import com.android.settings.bluetooth.BluetoothEnabler;
58import com.android.settings.bluetooth.BluetoothSettings;
59import com.android.settings.wifi.WifiEnabler;
60import com.android.settings.wifi.WifiSettings;
61import com.android.settings.wifi.p2p.WifiP2pSettings;
62
Gilles Debunnee78c1872011-06-20 15:00:07 -070063import java.util.ArrayList;
Amith Yamasanid1ab8282012-05-18 09:50:08 -070064import java.util.Collections;
65import java.util.Comparator;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070066import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070067import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -070068
69/**
70 * Top-level settings activity to handle single pane and double pane UI layout.
71 */
Amith Yamasani56821db2012-06-05 13:20:45 -070072public class Settings extends PreferenceActivity
73 implements ButtonBarHandler, OnAccountsUpdateListener {
Amith Yamasanid7993472010-08-18 13:59:28 -070074
Gilles Debunnee78c1872011-06-20 15:00:07 -070075 private static final String LOG_TAG = "Settings";
Amith Yamasaniea7b28c2012-06-20 13:51:40 -070076
Amith Yamasani5203bdf2010-11-04 09:59:44 -070077 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -070078 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -070079 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -070080 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080081 private static final String META_DATA_KEY_PARENT_TITLE =
82 "com.android.settings.PARENT_FRAGMENT_TITLE";
83 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
84 "com.android.settings.PARENT_FRAGMENT_CLASS";
85
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -080086 private static final String EXTRA_UI_OPTIONS = "settings:ui_options";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -070087
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080088 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
89 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -070090
91 private String mFragmentClass;
92 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -080093 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080094 private Header mCurrentHeader;
95 private Header mParentHeader;
96 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070097
Amith Yamasanib810a0d2012-03-25 10:12:26 -070098 // Show only these settings for restricted users
99 private int[] SETTINGS_FOR_RESTRICTED = {
Amith Yamasani32630392012-08-10 19:31:39 -0700100 R.id.wireless_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700101 R.id.wifi_settings,
102 R.id.bluetooth_settings,
Jeff Sharkey38305fb2012-09-14 16:26:51 -0700103 R.id.data_usage_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700104 R.id.wireless_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700105 R.id.device_section,
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700106 R.id.sound_settings,
107 R.id.display_settings,
Jeff Sharkey90c8b202012-08-30 15:20:10 -0700108 R.id.storage_settings,
Dianne Hackborn271c8b02012-08-20 17:24:39 -0700109 R.id.application_settings,
Dianne Hackborn52e56a22012-09-12 17:02:23 -0700110 R.id.battery_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700111 R.id.personal_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700112 R.id.location_settings,
Amith Yamasani3deeeb72012-04-05 14:44:48 -0700113 R.id.security_settings,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700114 R.id.language_settings,
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700115 R.id.user_settings,
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700116 R.id.account_settings,
Amith Yamasani32630392012-08-10 19:31:39 -0700117 R.id.account_add,
118 R.id.system_section,
Amith Yamasani9627a8e2012-09-23 12:54:14 -0700119 R.id.date_time_settings,
Jeff Brown9e143f52012-09-19 20:46:07 -0700120 R.id.about_settings,
Svetoslav Ganov46045d82012-09-20 15:04:55 -0700121 R.id.accessibility_settings
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700122 };
123
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700124 private SharedPreferences mDevelopmentPreferences;
125 private SharedPreferences.OnSharedPreferenceChangeListener mDevelopmentPreferencesListener;
126
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700127 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -0700128
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700129 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
130
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700131 private AuthenticatorHelper mAuthenticatorHelper;
132 private Header mLastHeader;
Amith Yamasani86708a82012-06-06 20:23:08 -0700133 private boolean mListeningToAccountUpdates;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700134
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700135 @Override
136 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800137 if (getIntent().hasExtra(EXTRA_UI_OPTIONS)) {
138 getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700139 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700140
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700141 mAuthenticatorHelper = new AuthenticatorHelper();
142 mAuthenticatorHelper.updateAuthDescriptions(this);
143 mAuthenticatorHelper.onAccountsUpdated(this, null);
144
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700145 mDevelopmentPreferences = getSharedPreferences(DevelopmentSettings.PREF_FILE,
146 Context.MODE_PRIVATE);
147
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700148 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800149 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700150 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800151 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700152
Gilles Debunne3661b622011-06-27 11:19:16 -0700153 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700154 highlightHeader(mTopLevelHeaderId);
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800155 // Force the title so that it doesn't get overridden by a direct launch of
156 // a specific settings screen.
157 setTitle(R.string.settings_label);
158 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800159
160 // Retrieve any saved state
161 if (savedInstanceState != null) {
162 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
163 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
164 }
165
166 // If the current header was saved, switch to it
167 if (savedInstanceState != null && mCurrentHeader != null) {
168 //switchToHeaderLocal(mCurrentHeader);
169 showBreadCrumbs(mCurrentHeader.title, null);
170 }
171
172 if (mParentHeader != null) {
173 setParentTitle(mParentHeader.title, null, new OnClickListener() {
174 public void onClick(View v) {
175 switchToParent(mParentHeader.fragment);
176 }
177 });
178 }
Gilles Debunnedc7101f2011-06-27 12:00:49 -0700179
Amith Yamasani3d384f42012-05-11 15:22:04 -0700180 // Override up navigation for multi-pane, since we handle it in the fragment breadcrumbs
181 if (onIsMultiPane()) {
182 getActionBar().setDisplayHomeAsUpEnabled(false);
183 getActionBar().setHomeButtonEnabled(false);
184 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800185 }
186
187 @Override
188 protected void onSaveInstanceState(Bundle outState) {
189 super.onSaveInstanceState(outState);
190
191 // Save the current fragment, if it is the same as originally launched
192 if (mCurrentHeader != null) {
193 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
194 }
195 if (mParentHeader != null) {
196 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
197 }
198 }
199
Gilles Debunnee78c1872011-06-20 15:00:07 -0700200 @Override
201 public void onResume() {
202 super.onResume();
203
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700204 mDevelopmentPreferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
205 @Override
206 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
207 invalidateHeaders();
208 }
209 };
210 mDevelopmentPreferences.registerOnSharedPreferenceChangeListener(
211 mDevelopmentPreferencesListener);
212
Gilles Debunnee78c1872011-06-20 15:00:07 -0700213 ListAdapter listAdapter = getListAdapter();
214 if (listAdapter instanceof HeaderAdapter) {
215 ((HeaderAdapter) listAdapter).resume();
216 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700217 invalidateHeaders();
Gilles Debunnee78c1872011-06-20 15:00:07 -0700218 }
219
220 @Override
221 public void onPause() {
222 super.onPause();
223
224 ListAdapter listAdapter = getListAdapter();
225 if (listAdapter instanceof HeaderAdapter) {
226 ((HeaderAdapter) listAdapter).pause();
Amith Yamasani86708a82012-06-06 20:23:08 -0700227 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700228
229 mDevelopmentPreferences.unregisterOnSharedPreferenceChangeListener(
230 mDevelopmentPreferencesListener);
231 mDevelopmentPreferencesListener = null;
Amith Yamasani86708a82012-06-06 20:23:08 -0700232 }
233
234 @Override
235 public void onDestroy() {
236 super.onDestroy();
237 if (mListeningToAccountUpdates) {
Amith Yamasani56821db2012-06-05 13:20:45 -0700238 AccountManager.get(this).removeOnAccountsUpdatedListener(this);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700239 }
240 }
241
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800242 private void switchToHeaderLocal(Header header) {
243 mInLocalHeaderSwitch = true;
244 switchToHeader(header);
245 mInLocalHeaderSwitch = false;
246 }
247
248 @Override
249 public void switchToHeader(Header header) {
250 if (!mInLocalHeaderSwitch) {
251 mCurrentHeader = null;
252 mParentHeader = null;
253 }
254 super.switchToHeader(header);
255 }
256
257 /**
258 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800259 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800260 */
261 private void switchToParent(String className) {
262 final ComponentName cn = new ComponentName(this, className);
263 try {
264 final PackageManager pm = getPackageManager();
265 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
266
267 if (parentInfo != null && parentInfo.metaData != null) {
268 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
269 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
270 Header parentHeader = new Header();
271 parentHeader.fragment = fragmentClass;
272 parentHeader.title = fragmentTitle;
273 mCurrentHeader = parentHeader;
274
275 switchToHeaderLocal(parentHeader);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700276 highlightHeader(mTopLevelHeaderId);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800277
278 mParentHeader = new Header();
279 mParentHeader.fragment
280 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
281 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
282 }
283 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700284 Log.w(LOG_TAG, "Could not find parent activity : " + className);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800285 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700286 }
287
Amith Yamasani3965ae62010-11-15 14:45:19 -0800288 @Override
289 public void onNewIntent(Intent intent) {
290 super.onNewIntent(intent);
291
292 // If it is not launched from history, then reset to top-level
Amith Yamasanief617232012-10-09 16:57:25 -0700293 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
294 if (mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
295 switchToHeaderLocal(mFirstHeader);
296 }
297 getListView().setSelectionFromTop(0, 0);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800298 }
299 }
300
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700301 private void highlightHeader(int id) {
302 if (id != 0) {
303 Integer index = mHeaderIndexMap.get(id);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700304 if (index != null) {
305 getListView().setItemChecked(index, true);
Amith Yamasanief617232012-10-09 16:57:25 -0700306 if (isMultiPane()) {
307 getListView().smoothScrollToPosition(index);
308 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700309 }
310 }
311 }
312
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700313 @Override
314 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700315 Intent superIntent = super.getIntent();
316 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700317 // This is called from super.onCreate, isMultiPane() is not yet reliable
318 // Do not use onIsHidingHeaders either, which relies itself on this method
319 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700320 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700321 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700322 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700323 if (args != null) {
324 args = new Bundle(args);
325 } else {
326 args = new Bundle();
327 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700328 args.putParcelable("intent", superIntent);
329 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700330 return modIntent;
331 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700332 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700333 }
334
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700335 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700336 * Checks if the component name in the intent is different from the Settings class and
337 * returns the class name to load as a fragment.
338 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700339 protected String getStartingFragmentClass(Intent intent) {
340 if (mFragmentClass != null) return mFragmentClass;
341
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700342 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700343 if (intentClass.equals(getClass().getName())) return null;
344
Dianne Hackbornee293792010-11-01 12:32:33 -0700345 if ("com.android.settings.ManageApplications".equals(intentClass)
346 || "com.android.settings.RunningServices".equals(intentClass)
347 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700348 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700349 intentClass = com.android.settings.applications.ManageApplications.class.getName();
350 }
351
Amith Yamasani379d9b02010-09-27 12:03:59 -0700352 return intentClass;
353 }
354
355 /**
356 * Override initial header when an activity-alias is causing Settings to be launched
357 * for a specific fragment encoded in the android:name parameter.
358 */
359 @Override
360 public Header onGetInitialHeader() {
361 String fragmentClass = getStartingFragmentClass(super.getIntent());
362 if (fragmentClass != null) {
363 Header header = new Header();
364 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800365 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700366 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800367 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700368 return header;
369 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700370
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700371 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700372 }
373
Dianne Hackbornb7258182011-03-15 16:23:55 -0700374 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700375 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
376 int titleRes, int shortTitleRes) {
377 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
378 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700379
Jeff Sharkeycc0d26b2012-11-27 16:42:27 -0800380 // Some fragments want split ActionBar; these should stay in sync with
381 // uiOptions for fragments also defined as activities in manifest.
382 if (WifiSettings.class.getName().equals(fragmentName) ||
383 WifiP2pSettings.class.getName().equals(fragmentName) ||
384 BluetoothSettings.class.getName().equals(fragmentName) ||
385 DreamSettings.class.getName().equals(fragmentName) ||
386 ToggleAccessibilityServicePreferenceFragment.class.getName().equals(fragmentName)) {
387 intent.putExtra(EXTRA_UI_OPTIONS, ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700388 }
389
Dianne Hackbornb7258182011-03-15 16:23:55 -0700390 intent.setClass(this, SubSettings.class);
391 return intent;
392 }
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700393
Amith Yamasani379d9b02010-09-27 12:03:59 -0700394 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700395 * Populate the activity with the top-level headers.
396 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700397 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700398 public void onBuildHeaders(List<Header> headers) {
399 loadHeadersFromResource(R.xml.settings_headers, headers);
Amith Yamasanid7993472010-08-18 13:59:28 -0700400
Gilles Debunnee78c1872011-06-20 15:00:07 -0700401 updateHeaderList(headers);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700402 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700403
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700404 private void updateHeaderList(List<Header> target) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700405 final boolean showDev = mDevelopmentPreferences.getBoolean(
406 DevelopmentSettings.PREF_SHOW,
407 android.os.Build.TYPE.equals("eng"));
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700408 int i = 0;
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700409
410 mHeaderIndexMap.clear();
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700411 while (i < target.size()) {
412 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700413 // Ids are integers, so downcasting
414 int id = (int) header.id;
Chris Wren2bc32ae2012-09-24 14:23:46 -0400415 if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700416 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700417 } else if (id == R.id.wifi_settings) {
418 // Remove WiFi Settings if WiFi service is not available.
419 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700420 target.remove(i);
Gilles Debunne2454f492011-06-21 16:16:06 -0700421 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700422 } else if (id == R.id.bluetooth_settings) {
423 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700424 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700425 target.remove(i);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700426 }
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700427 } else if (id == R.id.data_usage_settings) {
428 // Remove data usage when kernel module not enabled
429 final INetworkManagementService netManager = INetworkManagementService.Stub
430 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
431 try {
432 if (!netManager.isBandwidthControlEnabled()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700433 target.remove(i);
Jeff Sharkey34e964d2012-04-21 15:41:48 -0700434 }
435 } catch (RemoteException e) {
436 // ignored
437 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700438 } else if (id == R.id.account_settings) {
439 int headerIndex = i + 1;
440 i = insertAccountsHeaders(target, headerIndex);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700441 } else if (id == R.id.user_settings) {
Amith Yamasanidc6bfa62012-09-06 18:04:06 -0700442 if (!UserHandle.MU_ENABLED
Jeff Sharkey44202462012-09-19 13:13:45 -0700443 || !UserManager.supportsMultipleUsers()
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700444 || Utils.isMonkeyRunning()) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700445 target.remove(i);
446 }
447 } else if (id == R.id.development_settings) {
448 if (!showDev) {
449 target.remove(i);
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700450 }
451 }
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700452
Amith Yamasanib99f8642012-10-10 21:41:12 -0700453 if (target.get(i) == header
454 && UserHandle.MU_ENABLED && UserHandle.myUserId() != 0
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700455 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
Dianne Hackborncaefa9b2012-10-10 15:05:42 -0700456 target.remove(i);
Amith Yamasanid7993472010-08-18 13:59:28 -0700457 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700458
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700459 // Increment if the current one wasn't removed by the Utils code.
460 if (target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800461 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700462 if (mFirstHeader == null &&
463 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
464 mFirstHeader = header;
465 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700466 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700467 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700468 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700469 }
470 }
471
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700472 private int insertAccountsHeaders(List<Header> target, int headerIndex) {
473 String[] accountTypes = mAuthenticatorHelper.getEnabledAccountTypes();
474 List<Header> accountHeaders = new ArrayList<Header>(accountTypes.length);
475 for (String accountType : accountTypes) {
476 CharSequence label = mAuthenticatorHelper.getLabelForType(this, accountType);
Brian Muramatsuc28af522012-06-28 14:25:14 -0700477 if (label == null) {
478 continue;
479 }
480
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700481 Account[] accounts = AccountManager.get(this).getAccountsByType(accountType);
482 boolean skipToAccount = accounts.length == 1
483 && !mAuthenticatorHelper.hasAccountPreferences(accountType);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700484 Header accHeader = new Header();
485 accHeader.title = label;
486 if (accHeader.extras == null) {
487 accHeader.extras = new Bundle();
488 }
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700489 if (skipToAccount) {
490 accHeader.breadCrumbTitleRes = R.string.account_sync_settings_title;
491 accHeader.breadCrumbShortTitleRes = R.string.account_sync_settings_title;
492 accHeader.fragment = AccountSyncSettings.class.getName();
493 accHeader.fragmentArguments = new Bundle();
494 // Need this for the icon
495 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
496 accHeader.extras.putParcelable(AccountSyncSettings.ACCOUNT_KEY, accounts[0]);
497 accHeader.fragmentArguments.putParcelable(AccountSyncSettings.ACCOUNT_KEY,
498 accounts[0]);
499 } else {
500 accHeader.breadCrumbTitle = label;
501 accHeader.breadCrumbShortTitle = label;
502 accHeader.fragment = ManageAccountsSettings.class.getName();
503 accHeader.fragmentArguments = new Bundle();
504 accHeader.extras.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE, accountType);
505 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_TYPE,
506 accountType);
507 if (!isMultiPane()) {
508 accHeader.fragmentArguments.putString(ManageAccountsSettings.KEY_ACCOUNT_LABEL,
509 label.toString());
510 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700511 }
512 accountHeaders.add(accHeader);
513 }
514
515 // Sort by label
516 Collections.sort(accountHeaders, new Comparator<Header>() {
517 @Override
518 public int compare(Header h1, Header h2) {
519 return h1.title.toString().compareTo(h2.title.toString());
520 }
521 });
522
523 for (Header header : accountHeaders) {
524 target.add(headerIndex++, header);
525 }
Amith Yamasani86708a82012-06-06 20:23:08 -0700526 if (!mListeningToAccountUpdates) {
527 AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);
528 mListeningToAccountUpdates = true;
529 }
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700530 return headerIndex;
531 }
532
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700533 private void getMetaData() {
534 try {
535 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
536 PackageManager.GET_META_DATA);
537 if (ai == null || ai.metaData == null) return;
538 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
539 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700540
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800541 // Check if it has a parent specified and create a Header object
542 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
543 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
544 if (parentFragmentClass != null) {
545 mParentHeader = new Header();
546 mParentHeader.fragment = parentFragmentClass;
547 if (parentHeaderTitleRes != 0) {
548 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
549 }
550 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700551 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700552 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700553 }
554 }
555
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800556 @Override
557 public boolean hasNextButton() {
558 return super.hasNextButton();
559 }
560
561 @Override
562 public Button getNextButton() {
563 return super.getNextButton();
564 }
565
Gilles Debunnee78c1872011-06-20 15:00:07 -0700566 private static class HeaderAdapter extends ArrayAdapter<Header> {
567 static final int HEADER_TYPE_CATEGORY = 0;
568 static final int HEADER_TYPE_NORMAL = 1;
569 static final int HEADER_TYPE_SWITCH = 2;
570 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;
571
572 private final WifiEnabler mWifiEnabler;
573 private final BluetoothEnabler mBluetoothEnabler;
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700574 private AuthenticatorHelper mAuthHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700575
576 private static class HeaderViewHolder {
577 ImageView icon;
578 TextView title;
579 TextView summary;
580 Switch switch_;
581 }
582
583 private LayoutInflater mInflater;
584
585 static int getHeaderType(Header header) {
586 if (header.fragment == null && header.intent == null) {
587 return HEADER_TYPE_CATEGORY;
588 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
589 return HEADER_TYPE_SWITCH;
590 } else {
591 return HEADER_TYPE_NORMAL;
592 }
593 }
594
595 @Override
596 public int getItemViewType(int position) {
597 Header header = getItem(position);
598 return getHeaderType(header);
599 }
600
601 @Override
602 public boolean areAllItemsEnabled() {
603 return false; // because of categories
604 }
605
606 @Override
607 public boolean isEnabled(int position) {
608 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
609 }
610
611 @Override
612 public int getViewTypeCount() {
613 return HEADER_TYPE_COUNT;
614 }
615
616 @Override
617 public boolean hasStableIds() {
618 return true;
619 }
620
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700621 public HeaderAdapter(Context context, List<Header> objects,
622 AuthenticatorHelper authenticatorHelper) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700623 super(context, 0, objects);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700624
625 mAuthHelper = authenticatorHelper;
Gilles Debunnee78c1872011-06-20 15:00:07 -0700626 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700627
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700628 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700629 // Switches inflated from their layouts. Must be done before adapter is set in super
630 mWifiEnabler = new WifiEnabler(context, new Switch(context));
631 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
632 }
633
634 @Override
635 public View getView(int position, View convertView, ViewGroup parent) {
636 HeaderViewHolder holder;
637 Header header = getItem(position);
638 int headerType = getHeaderType(header);
639 View view = null;
640
641 if (convertView == null) {
642 holder = new HeaderViewHolder();
643 switch (headerType) {
644 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700645 view = new TextView(getContext(), null,
646 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700647 holder.title = (TextView) view;
648 break;
649
650 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700651 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
652 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700653 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700654 holder.title = (TextView)
655 view.findViewById(com.android.internal.R.id.title);
656 holder.summary = (TextView)
657 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700658 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
659 break;
660
661 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700662 view = mInflater.inflate(
Amith Yamasanic8a93172012-06-08 13:35:47 -0700663 R.layout.preference_header_item, parent,
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700664 false);
Amith Yamasanic8a93172012-06-08 13:35:47 -0700665 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700666 holder.title = (TextView)
667 view.findViewById(com.android.internal.R.id.title);
668 holder.summary = (TextView)
669 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700670 break;
671 }
672 view.setTag(holder);
673 } else {
674 view = convertView;
675 holder = (HeaderViewHolder) view.getTag();
676 }
677
678 // All view fields must be updated every time, because the view may be recycled
679 switch (headerType) {
680 case HEADER_TYPE_CATEGORY:
681 holder.title.setText(header.getTitle(getContext().getResources()));
682 break;
683
684 case HEADER_TYPE_SWITCH:
685 // Would need a different treatment if the main menu had more switches
686 if (header.id == R.id.wifi_settings) {
687 mWifiEnabler.setSwitch(holder.switch_);
688 } else {
689 mBluetoothEnabler.setSwitch(holder.switch_);
690 }
691 // No break, fall through on purpose to update common fields
692
693 //$FALL-THROUGH$
694 case HEADER_TYPE_NORMAL:
Amith Yamasani3882c2e2012-06-07 17:03:20 -0700695 if (header.extras != null
696 && header.extras.containsKey(ManageAccountsSettings.KEY_ACCOUNT_TYPE)) {
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700697 String accType = header.extras.getString(
698 ManageAccountsSettings.KEY_ACCOUNT_TYPE);
699 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
700 lp.width = getContext().getResources().getDimensionPixelSize(
701 R.dimen.header_icon_width);
702 lp.height = lp.width;
703 holder.icon.setLayoutParams(lp);
704 Drawable icon = mAuthHelper.getDrawableForType(getContext(), accType);
705 holder.icon.setImageDrawable(icon);
706 } else {
707 holder.icon.setImageResource(header.iconRes);
708 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700709 holder.title.setText(header.getTitle(getContext().getResources()));
710 CharSequence summary = header.getSummary(getContext().getResources());
711 if (!TextUtils.isEmpty(summary)) {
712 holder.summary.setVisibility(View.VISIBLE);
713 holder.summary.setText(summary);
714 } else {
715 holder.summary.setVisibility(View.GONE);
716 }
717 break;
718 }
719
720 return view;
721 }
722
723 public void resume() {
724 mWifiEnabler.resume();
725 mBluetoothEnabler.resume();
726 }
Brian Muramatsuc28af522012-06-28 14:25:14 -0700727
Gilles Debunnee78c1872011-06-20 15:00:07 -0700728 public void pause() {
729 mWifiEnabler.pause();
730 mBluetoothEnabler.pause();
731 }
732 }
733
734 @Override
Amith Yamasanid1ab8282012-05-18 09:50:08 -0700735 public void onHeaderClick(Header header, int position) {
736 boolean revert = false;
737 if (header.id == R.id.account_add) {
738 revert = true;
739 }
740
741 super.onHeaderClick(header, position);
742
743 if (revert && mLastHeader != null) {
744 highlightHeader((int) mLastHeader.id);
745 } else {
746 mLastHeader = header;
747 }
748 }
749
750 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700751 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
752 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800753 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700754 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800755 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasani8666b9e2012-09-27 14:50:13 -0700756 } else if (pref.getFragment().equals(OwnerInfoSettings.class.getName())
757 && UserHandle.myUserId() != UserHandle.USER_OWNER) {
758 titleRes = R.string.user_info_settings_title;
Amith Yamasania4379d62011-07-22 10:34:58 -0700759 }
Jean Chalard7dabe452012-05-10 18:08:07 +0900760 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, pref.getTitle(),
761 null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -0700762 return true;
763 }
764
Amith Yamasani3d384f42012-05-11 15:22:04 -0700765 public boolean shouldUpRecreateTask(Intent targetIntent) {
766 return super.shouldUpRecreateTask(new Intent(this, Settings.class));
767 }
768
Amith Yamasania4379d62011-07-22 10:34:58 -0700769 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700770 public void setListAdapter(ListAdapter adapter) {
Amith Yamasaniea7b28c2012-06-20 13:51:40 -0700771 if (adapter == null) {
772 super.setListAdapter(null);
773 } else {
774 super.setListAdapter(new HeaderAdapter(this, getHeaders(), mAuthenticatorHelper));
Gilles Debunnee78c1872011-06-20 15:00:07 -0700775 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700776 }
777
Amith Yamasani56821db2012-06-05 13:20:45 -0700778 @Override
779 public void onAccountsUpdated(Account[] accounts) {
Jeff Sharkey9ff79c12012-10-03 16:48:17 -0700780 // TODO: watch for package upgrades to invalidate cache; see 7206643
781 mAuthenticatorHelper.updateAuthDescriptions(this);
Amith Yamasani56821db2012-06-05 13:20:45 -0700782 mAuthenticatorHelper.onAccountsUpdated(this, accounts);
783 invalidateHeaders();
784 }
785
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700786 /*
787 * Settings subclasses for launching independently.
788 */
Gilles Debunnee78c1872011-06-20 15:00:07 -0700789 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
790 public static class WirelessSettingsActivity extends Settings { /* empty */ }
791 public static class TetherSettingsActivity extends Settings { /* empty */ }
792 public static class VpnSettingsActivity extends Settings { /* empty */ }
793 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
794 public static class StorageSettingsActivity extends Settings { /* empty */ }
795 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -0700796 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700797 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Jeff Browne46c5f32012-04-05 11:42:18 -0700798 public static class KeyboardLayoutPickerActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700799 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +0900800 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700801 public static class LocalePickerActivity extends Settings { /* empty */ }
802 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
803 public static class SoundSettingsActivity extends Settings { /* empty */ }
804 public static class DisplaySettingsActivity extends Settings { /* empty */ }
805 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
806 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
807 public static class ManageApplicationsActivity extends Settings { /* empty */ }
808 public static class StorageUseActivity extends Settings { /* empty */ }
809 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
810 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
811 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -0700812 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700813 public static class PrivacySettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700814 public static class RunningServicesActivity extends Settings { /* empty */ }
815 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
816 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
817 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
818 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
819 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
820 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
821 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -0700822 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -0700823 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -0500824 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
Jeff Brown9e143f52012-09-19 20:46:07 -0700825 public static class WifiDisplaySettingsActivity extends Settings { /* empty */ }
Daniel Sandler7dee75c2012-11-27 22:41:30 -0500826 public static class DreamSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800827}