blob: 7e4e725a39dc3c4d2c9b48ff7ef4a1725285d31b [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 Yamasanib810a0d2012-03-25 10:12:26 -070019import com.android.internal.util.ArrayUtils;
Gilles Debunnecd8e5242011-07-25 11:36:15 -070020import com.android.settings.accounts.AccountSyncSettings;
21import com.android.settings.bluetooth.BluetoothEnabler;
Jeff Sharkey11d30122012-03-19 16:54:07 -070022import com.android.settings.deviceinfo.Memory;
Gilles Debunnecd8e5242011-07-25 11:36:15 -070023import com.android.settings.fuelgauge.PowerUsageSummary;
24import com.android.settings.wifi.WifiEnabler;
25
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080026import android.content.ComponentName;
Gilles Debunnee78c1872011-06-20 15:00:07 -070027import android.content.Context;
Amith Yamasani379d9b02010-09-27 12:03:59 -070028import android.content.Intent;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070029import android.content.pm.ActivityInfo;
30import android.content.pm.PackageManager;
31import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070032import android.os.Bundle;
Amith Yamasanib810a0d2012-03-25 10:12:26 -070033import android.os.UserId;
Amith Yamasania4379d62011-07-22 10:34:58 -070034import android.preference.Preference;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070035import android.preference.PreferenceActivity;
Amith Yamasania4379d62011-07-22 10:34:58 -070036import android.preference.PreferenceFragment;
Gilles Debunnee78c1872011-06-20 15:00:07 -070037import android.text.TextUtils;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080038import android.util.Log;
Gilles Debunnee78c1872011-06-20 15:00:07 -070039import android.view.LayoutInflater;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080040import android.view.View;
41import android.view.View.OnClickListener;
Gilles Debunnee78c1872011-06-20 15:00:07 -070042import android.view.ViewGroup;
43import android.widget.ArrayAdapter;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080044import android.widget.Button;
Gilles Debunnee78c1872011-06-20 15:00:07 -070045import android.widget.ImageView;
46import android.widget.ListAdapter;
47import android.widget.Switch;
48import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080049
Gilles Debunnee78c1872011-06-20 15:00:07 -070050import java.util.ArrayList;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070051import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070052import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -070053
54/**
55 * Top-level settings activity to handle single pane and double pane UI layout.
56 */
Daisuke Miyakawa79c5fd92011-01-15 14:58:00 -080057public class Settings extends PreferenceActivity implements ButtonBarHandler {
Amith Yamasanid7993472010-08-18 13:59:28 -070058
Gilles Debunnee78c1872011-06-20 15:00:07 -070059 private static final String LOG_TAG = "Settings";
Amith Yamasani5203bdf2010-11-04 09:59:44 -070060 private static final String META_DATA_KEY_HEADER_ID =
Gilles Debunnee78c1872011-06-20 15:00:07 -070061 "com.android.settings.TOP_LEVEL_HEADER_ID";
Amith Yamasani5203bdf2010-11-04 09:59:44 -070062 private static final String META_DATA_KEY_FRAGMENT_CLASS =
Gilles Debunnee78c1872011-06-20 15:00:07 -070063 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080064 private static final String META_DATA_KEY_PARENT_TITLE =
65 "com.android.settings.PARENT_FRAGMENT_TITLE";
66 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
67 "com.android.settings.PARENT_FRAGMENT_CLASS";
68
Jeff Sharkey54d0af52011-08-11 18:26:57 -070069 private static final String EXTRA_CLEAR_UI_OPTIONS = "settings:remove_ui_options";
Jeff Sharkey9fab0da2011-07-09 17:52:31 -070070
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080071 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
72 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -070073
74 private String mFragmentClass;
75 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -080076 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080077 private Header mCurrentHeader;
78 private Header mParentHeader;
79 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070080
Amith Yamasanib810a0d2012-03-25 10:12:26 -070081 // Show only these settings for restricted users
82 private int[] SETTINGS_FOR_RESTRICTED = {
83 R.id.wifi_settings,
84 R.id.bluetooth_settings,
85 R.id.sound_settings,
86 R.id.display_settings,
87 //R.id.security_settings,
88 R.id.sync_settings,
89 R.id.about_settings
90 };
91
Amith Yamasani02cf71a2010-09-21 15:48:52 -070092 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -070093
Amith Yamasani5203bdf2010-11-04 09:59:44 -070094 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
Gilles Debunnee78c1872011-06-20 15:00:07 -070095 private List<Header> mHeaders;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070096
97 @Override
98 protected void onCreate(Bundle savedInstanceState) {
Jeff Sharkey54d0af52011-08-11 18:26:57 -070099 if (getIntent().getBooleanExtra(EXTRA_CLEAR_UI_OPTIONS, false)) {
100 getWindow().setUiOptions(0);
101 }
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700102
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700103 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800104 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700105 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800106 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700107
Gilles Debunne3661b622011-06-27 11:19:16 -0700108 if (!onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasani72aa19d2010-12-09 06:07:12 -0800109 highlightHeader();
110 // Force the title so that it doesn't get overridden by a direct launch of
111 // a specific settings screen.
112 setTitle(R.string.settings_label);
113 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800114
115 // Retrieve any saved state
116 if (savedInstanceState != null) {
117 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
118 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
119 }
120
121 // If the current header was saved, switch to it
122 if (savedInstanceState != null && mCurrentHeader != null) {
123 //switchToHeaderLocal(mCurrentHeader);
124 showBreadCrumbs(mCurrentHeader.title, null);
125 }
126
127 if (mParentHeader != null) {
128 setParentTitle(mParentHeader.title, null, new OnClickListener() {
129 public void onClick(View v) {
130 switchToParent(mParentHeader.fragment);
131 }
132 });
133 }
Gilles Debunnedc7101f2011-06-27 12:00:49 -0700134
135 // TODO Add support for android.R.id.home in all Setting's onOptionsItemSelected
136 // getActionBar().setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP,
137 // ActionBar.DISPLAY_HOME_AS_UP);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800138 }
139
140 @Override
141 protected void onSaveInstanceState(Bundle outState) {
142 super.onSaveInstanceState(outState);
143
144 // Save the current fragment, if it is the same as originally launched
145 if (mCurrentHeader != null) {
146 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
147 }
148 if (mParentHeader != null) {
149 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
150 }
151 }
152
Gilles Debunnee78c1872011-06-20 15:00:07 -0700153 @Override
154 public void onResume() {
155 super.onResume();
156
157 ListAdapter listAdapter = getListAdapter();
158 if (listAdapter instanceof HeaderAdapter) {
159 ((HeaderAdapter) listAdapter).resume();
160 }
161 }
162
163 @Override
164 public void onPause() {
165 super.onPause();
166
167 ListAdapter listAdapter = getListAdapter();
168 if (listAdapter instanceof HeaderAdapter) {
169 ((HeaderAdapter) listAdapter).pause();
170 }
171 }
172
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800173 private void switchToHeaderLocal(Header header) {
174 mInLocalHeaderSwitch = true;
175 switchToHeader(header);
176 mInLocalHeaderSwitch = false;
177 }
178
179 @Override
180 public void switchToHeader(Header header) {
181 if (!mInLocalHeaderSwitch) {
182 mCurrentHeader = null;
183 mParentHeader = null;
184 }
185 super.switchToHeader(header);
186 }
187
188 /**
189 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800190 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800191 */
192 private void switchToParent(String className) {
193 final ComponentName cn = new ComponentName(this, className);
194 try {
195 final PackageManager pm = getPackageManager();
196 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
197
198 if (parentInfo != null && parentInfo.metaData != null) {
199 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
200 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
201 Header parentHeader = new Header();
202 parentHeader.fragment = fragmentClass;
203 parentHeader.title = fragmentTitle;
204 mCurrentHeader = parentHeader;
205
206 switchToHeaderLocal(parentHeader);
Amith Yamasani990fb522011-09-02 09:47:18 -0700207 highlightHeader();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800208
209 mParentHeader = new Header();
210 mParentHeader.fragment
211 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
212 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
213 }
214 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700215 Log.w(LOG_TAG, "Could not find parent activity : " + className);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800216 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700217 }
218
Amith Yamasani3965ae62010-11-15 14:45:19 -0800219 @Override
220 public void onNewIntent(Intent intent) {
221 super.onNewIntent(intent);
222
223 // If it is not launched from history, then reset to top-level
224 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0
Gilles Debunne3661b622011-06-27 11:19:16 -0700225 && mFirstHeader != null && !onIsHidingHeaders() && onIsMultiPane()) {
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800226 switchToHeaderLocal(mFirstHeader);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800227 }
228 }
229
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700230 private void highlightHeader() {
231 if (mTopLevelHeaderId != 0) {
232 Integer index = mHeaderIndexMap.get(mTopLevelHeaderId);
233 if (index != null) {
234 getListView().setItemChecked(index, true);
Amith Yamasani990fb522011-09-02 09:47:18 -0700235 getListView().smoothScrollToPosition(index);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700236 }
237 }
238 }
239
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700240 @Override
241 public Intent getIntent() {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700242 Intent superIntent = super.getIntent();
243 String startingFragment = getStartingFragmentClass(superIntent);
Gilles Debunne3661b622011-06-27 11:19:16 -0700244 // This is called from super.onCreate, isMultiPane() is not yet reliable
245 // Do not use onIsHidingHeaders either, which relies itself on this method
246 if (startingFragment != null && !onIsMultiPane()) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700247 Intent modIntent = new Intent(superIntent);
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700248 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700249 Bundle args = superIntent.getExtras();
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700250 if (args != null) {
251 args = new Bundle(args);
252 } else {
253 args = new Bundle();
254 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700255 args.putParcelable("intent", superIntent);
256 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700257 return modIntent;
258 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700259 return superIntent;
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700260 }
261
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700262 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700263 * Checks if the component name in the intent is different from the Settings class and
264 * returns the class name to load as a fragment.
265 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700266 protected String getStartingFragmentClass(Intent intent) {
267 if (mFragmentClass != null) return mFragmentClass;
268
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700269 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700270 if (intentClass.equals(getClass().getName())) return null;
271
Dianne Hackbornee293792010-11-01 12:32:33 -0700272 if ("com.android.settings.ManageApplications".equals(intentClass)
273 || "com.android.settings.RunningServices".equals(intentClass)
274 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700275 // Old names of manage apps.
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700276 intentClass = com.android.settings.applications.ManageApplications.class.getName();
277 }
278
Amith Yamasani379d9b02010-09-27 12:03:59 -0700279 return intentClass;
280 }
281
282 /**
283 * Override initial header when an activity-alias is causing Settings to be launched
284 * for a specific fragment encoded in the android:name parameter.
285 */
286 @Override
287 public Header onGetInitialHeader() {
288 String fragmentClass = getStartingFragmentClass(super.getIntent());
289 if (fragmentClass != null) {
290 Header header = new Header();
291 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800292 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700293 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800294 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700295 return header;
296 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700297
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700298 return mFirstHeader;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700299 }
300
Dianne Hackbornb7258182011-03-15 16:23:55 -0700301 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700302 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
303 int titleRes, int shortTitleRes) {
304 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
305 titleRes, shortTitleRes);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700306
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700307 // some fragments want to avoid split actionbar
Gilles Debunne162e5412011-07-11 14:13:31 -0700308 if (DataUsageSummary.class.getName().equals(fragmentName) ||
309 PowerUsageSummary.class.getName().equals(fragmentName) ||
Gilles Debunnecd8e5242011-07-25 11:36:15 -0700310 AccountSyncSettings.class.getName().equals(fragmentName) ||
Jeff Sharkey11d30122012-03-19 16:54:07 -0700311 UserDictionarySettings.class.getName().equals(fragmentName) ||
312 Memory.class.getName().equals(fragmentName)) {
Jeff Sharkey54d0af52011-08-11 18:26:57 -0700313 intent.putExtra(EXTRA_CLEAR_UI_OPTIONS, true);
Jeff Sharkey9fab0da2011-07-09 17:52:31 -0700314 }
315
Dianne Hackbornb7258182011-03-15 16:23:55 -0700316 intent.setClass(this, SubSettings.class);
317 return intent;
318 }
319
Amith Yamasani379d9b02010-09-27 12:03:59 -0700320 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700321 * Populate the activity with the top-level headers.
322 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700323 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700324 public void onBuildHeaders(List<Header> headers) {
325 loadHeadersFromResource(R.xml.settings_headers, headers);
Amith Yamasanid7993472010-08-18 13:59:28 -0700326
Gilles Debunnee78c1872011-06-20 15:00:07 -0700327 updateHeaderList(headers);
328
329 mHeaders = headers;
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700330 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700331
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700332 private void updateHeaderList(List<Header> target) {
333 int i = 0;
334 while (i < target.size()) {
335 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700336 // Ids are integers, so downcasting
337 int id = (int) header.id;
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700338 if (id == R.id.dock_settings) {
339 if (!needsDockSettings())
340 target.remove(header);
341 } else if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
342 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
Gilles Debunne2454f492011-06-21 16:16:06 -0700343 } else if (id == R.id.wifi_settings) {
344 // Remove WiFi Settings if WiFi service is not available.
345 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
346 target.remove(header);
347 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700348 } else if (id == R.id.bluetooth_settings) {
349 // Remove Bluetooth Settings if Bluetooth service is not available.
Gilles Debunne2454f492011-06-21 16:16:06 -0700350 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700351 target.remove(header);
352 }
Amith Yamasanib810a0d2012-03-25 10:12:26 -0700353 } else if (id == R.id.user_settings) {
354 if (!UserId.MU_ENABLED || UserId.myUserId() != 0
355 || !getResources().getBoolean(R.bool.enable_user_management)
356 || Utils.isMonkeyRunning()) {
357 target.remove(header);
358 }
359 }
360 if (UserId.MU_ENABLED && UserId.myUserId() != 0
361 && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, id)) {
362 target.remove(header);
Amith Yamasanid7993472010-08-18 13:59:28 -0700363 }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700364
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700365 // Increment if the current one wasn't removed by the Utils code.
366 if (target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800367 // Hold on to the first header, when we need to reset to the top-level
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700368 if (mFirstHeader == null &&
369 HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY) {
370 mFirstHeader = header;
371 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700372 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700373 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700374 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700375 }
376 }
377
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700378 private boolean needsDockSettings() {
379 return getResources().getBoolean(R.bool.has_dock_settings);
Amith Yamasanib61cf512010-09-12 08:17:50 -0700380 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700381
382 private void getMetaData() {
383 try {
384 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
385 PackageManager.GET_META_DATA);
386 if (ai == null || ai.metaData == null) return;
387 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
388 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800389
390 // Check if it has a parent specified and create a Header object
391 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
392 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
393 if (parentFragmentClass != null) {
394 mParentHeader = new Header();
395 mParentHeader.fragment = parentFragmentClass;
396 if (parentHeaderTitleRes != 0) {
397 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
398 }
399 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700400 } catch (NameNotFoundException nnfe) {
Gilles Debunnee78c1872011-06-20 15:00:07 -0700401 // No recovery
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700402 }
403 }
404
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800405 @Override
406 public boolean hasNextButton() {
407 return super.hasNextButton();
408 }
409
410 @Override
411 public Button getNextButton() {
412 return super.getNextButton();
413 }
414
Gilles Debunnee78c1872011-06-20 15:00:07 -0700415 private static class HeaderAdapter extends ArrayAdapter<Header> {
416 static final int HEADER_TYPE_CATEGORY = 0;
417 static final int HEADER_TYPE_NORMAL = 1;
418 static final int HEADER_TYPE_SWITCH = 2;
419 private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;
420
421 private final WifiEnabler mWifiEnabler;
422 private final BluetoothEnabler mBluetoothEnabler;
423
424 private static class HeaderViewHolder {
425 ImageView icon;
426 TextView title;
427 TextView summary;
428 Switch switch_;
429 }
430
431 private LayoutInflater mInflater;
432
433 static int getHeaderType(Header header) {
434 if (header.fragment == null && header.intent == null) {
435 return HEADER_TYPE_CATEGORY;
436 } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
437 return HEADER_TYPE_SWITCH;
438 } else {
439 return HEADER_TYPE_NORMAL;
440 }
441 }
442
443 @Override
444 public int getItemViewType(int position) {
445 Header header = getItem(position);
446 return getHeaderType(header);
447 }
448
449 @Override
450 public boolean areAllItemsEnabled() {
451 return false; // because of categories
452 }
453
454 @Override
455 public boolean isEnabled(int position) {
456 return getItemViewType(position) != HEADER_TYPE_CATEGORY;
457 }
458
459 @Override
460 public int getViewTypeCount() {
461 return HEADER_TYPE_COUNT;
462 }
463
464 @Override
465 public boolean hasStableIds() {
466 return true;
467 }
468
469 public HeaderAdapter(Context context, List<Header> objects) {
470 super(context, 0, objects);
471 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
472
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700473 // Temp Switches provided as placeholder until the adapter replaces these with actual
Gilles Debunnee78c1872011-06-20 15:00:07 -0700474 // Switches inflated from their layouts. Must be done before adapter is set in super
475 mWifiEnabler = new WifiEnabler(context, new Switch(context));
476 mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
477 }
478
479 @Override
480 public View getView(int position, View convertView, ViewGroup parent) {
481 HeaderViewHolder holder;
482 Header header = getItem(position);
483 int headerType = getHeaderType(header);
484 View view = null;
485
486 if (convertView == null) {
487 holder = new HeaderViewHolder();
488 switch (headerType) {
489 case HEADER_TYPE_CATEGORY:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700490 view = new TextView(getContext(), null,
491 android.R.attr.listSeparatorTextViewStyle);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700492 holder.title = (TextView) view;
493 break;
494
495 case HEADER_TYPE_SWITCH:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700496 view = mInflater.inflate(R.layout.preference_header_switch_item, parent,
497 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700498 holder.icon = (ImageView) view.findViewById(R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700499 holder.title = (TextView)
500 view.findViewById(com.android.internal.R.id.title);
501 holder.summary = (TextView)
502 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700503 holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
504 break;
505
506 case HEADER_TYPE_NORMAL:
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700507 view = mInflater.inflate(
508 com.android.internal.R.layout.preference_header_item, parent,
509 false);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700510 holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
Gilles Debunneb396c9b2011-06-22 16:07:29 -0700511 holder.title = (TextView)
512 view.findViewById(com.android.internal.R.id.title);
513 holder.summary = (TextView)
514 view.findViewById(com.android.internal.R.id.summary);
Gilles Debunnee78c1872011-06-20 15:00:07 -0700515 break;
516 }
517 view.setTag(holder);
518 } else {
519 view = convertView;
520 holder = (HeaderViewHolder) view.getTag();
521 }
522
523 // All view fields must be updated every time, because the view may be recycled
524 switch (headerType) {
525 case HEADER_TYPE_CATEGORY:
526 holder.title.setText(header.getTitle(getContext().getResources()));
527 break;
528
529 case HEADER_TYPE_SWITCH:
530 // Would need a different treatment if the main menu had more switches
531 if (header.id == R.id.wifi_settings) {
532 mWifiEnabler.setSwitch(holder.switch_);
533 } else {
534 mBluetoothEnabler.setSwitch(holder.switch_);
535 }
536 // No break, fall through on purpose to update common fields
537
538 //$FALL-THROUGH$
539 case HEADER_TYPE_NORMAL:
540 holder.icon.setImageResource(header.iconRes);
541 holder.title.setText(header.getTitle(getContext().getResources()));
542 CharSequence summary = header.getSummary(getContext().getResources());
543 if (!TextUtils.isEmpty(summary)) {
544 holder.summary.setVisibility(View.VISIBLE);
545 holder.summary.setText(summary);
546 } else {
547 holder.summary.setVisibility(View.GONE);
548 }
549 break;
550 }
551
552 return view;
553 }
554
555 public void resume() {
556 mWifiEnabler.resume();
557 mBluetoothEnabler.resume();
558 }
559
560 public void pause() {
561 mWifiEnabler.pause();
562 mBluetoothEnabler.pause();
563 }
564 }
565
566 @Override
Amith Yamasania4379d62011-07-22 10:34:58 -0700567 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
568 // Override the fragment title for Wallpaper settings
Amith Yamasanidfb65432011-11-29 16:38:14 -0800569 int titleRes = pref.getTitleRes();
Amith Yamasania4379d62011-07-22 10:34:58 -0700570 if (pref.getFragment().equals(WallpaperTypeSettings.class.getName())) {
Amith Yamasanidfb65432011-11-29 16:38:14 -0800571 titleRes = R.string.wallpaper_settings_fragment_title;
Amith Yamasania4379d62011-07-22 10:34:58 -0700572 }
Amith Yamasanidfb65432011-11-29 16:38:14 -0800573 startPreferencePanel(pref.getFragment(), pref.getExtras(), titleRes, null, null, 0);
Amith Yamasania4379d62011-07-22 10:34:58 -0700574 return true;
575 }
576
577 @Override
Gilles Debunnee78c1872011-06-20 15:00:07 -0700578 public void setListAdapter(ListAdapter adapter) {
579 if (mHeaders == null) {
580 mHeaders = new ArrayList<Header>();
581 // When the saved state provides the list of headers, onBuildHeaders is not called
582 // Copy the list of Headers from the adapter, preserving their order
583 for (int i = 0; i < adapter.getCount(); i++) {
584 mHeaders.add((Header) adapter.getItem(i));
585 }
586 }
587
588 // Ignore the adapter provided by PreferenceActivity and substitute ours instead
589 super.setListAdapter(new HeaderAdapter(this, mHeaders));
590 }
591
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700592 /*
593 * Settings subclasses for launching independently.
594 */
Gilles Debunnee78c1872011-06-20 15:00:07 -0700595 public static class BluetoothSettingsActivity extends Settings { /* empty */ }
596 public static class WirelessSettingsActivity extends Settings { /* empty */ }
597 public static class TetherSettingsActivity extends Settings { /* empty */ }
598 public static class VpnSettingsActivity extends Settings { /* empty */ }
599 public static class DateTimeSettingsActivity extends Settings { /* empty */ }
600 public static class StorageSettingsActivity extends Settings { /* empty */ }
601 public static class WifiSettingsActivity extends Settings { /* empty */ }
repo syncb98463f2011-06-30 10:58:43 -0700602 public static class WifiP2pSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700603 public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700604 public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
satoke077d2b2011-07-25 09:38:11 +0900605 public static class SpellCheckersSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700606 public static class LocalePickerActivity extends Settings { /* empty */ }
607 public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
608 public static class SoundSettingsActivity extends Settings { /* empty */ }
609 public static class DisplaySettingsActivity extends Settings { /* empty */ }
610 public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
611 public static class ApplicationSettingsActivity extends Settings { /* empty */ }
612 public static class ManageApplicationsActivity extends Settings { /* empty */ }
613 public static class StorageUseActivity extends Settings { /* empty */ }
614 public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
615 public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
616 public static class SecuritySettingsActivity extends Settings { /* empty */ }
Gilles Debunnea6a8a142011-06-09 11:56:17 -0700617 public static class LocationSettingsActivity extends Settings { /* empty */ }
Gilles Debunnee78c1872011-06-20 15:00:07 -0700618 public static class PrivacySettingsActivity extends Settings { /* empty */ }
619 public static class DockSettingsActivity extends Settings { /* empty */ }
620 public static class RunningServicesActivity extends Settings { /* empty */ }
621 public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
622 public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
623 public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
624 public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
625 public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
626 public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
627 public static class DataUsageSummaryActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -0700628 public static class AdvancedWifiSettingsActivity extends Settings { /* empty */ }
Gilles Debunneab189bd2011-07-06 13:10:16 -0700629 public static class TextToSpeechSettingsActivity extends Settings { /* empty */ }
Jeff Hamilton3d670de2011-09-21 16:44:36 -0500630 public static class AndroidBeamSettingsActivity extends Settings { /* empty */ }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800631}