blob: c68ea5ddbfa98fcb98175916f0b1dc383001ae7a [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 Yamasanic9fdfa82010-12-14 14:38:16 -080019import android.content.ComponentName;
Amith Yamasani379d9b02010-09-27 12:03:59 -070020import android.content.Intent;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070021import android.content.pm.ActivityInfo;
22import android.content.pm.PackageManager;
23import android.content.pm.PackageManager.NameNotFoundException;
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -070024import android.os.Bundle;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070025import android.preference.PreferenceActivity;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080026import android.util.Log;
27import android.view.View;
28import android.view.View.OnClickListener;
Amith Yamasani9e3a4702011-01-11 09:09:26 -080029import android.widget.Button;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080030
Amith Yamasani5203bdf2010-11-04 09:59:44 -070031import java.util.HashMap;
Amith Yamasani02cf71a2010-09-21 15:48:52 -070032import java.util.List;
Amith Yamasanid7993472010-08-18 13:59:28 -070033
34/**
35 * Top-level settings activity to handle single pane and double pane UI layout.
36 */
Daisuke Miyakawa79c5fd92011-01-15 14:58:00 -080037public class Settings extends PreferenceActivity implements ButtonBarHandler {
Amith Yamasanid7993472010-08-18 13:59:28 -070038
Amith Yamasani5203bdf2010-11-04 09:59:44 -070039 private static final String META_DATA_KEY_HEADER_ID =
40 "com.android.settings.TOP_LEVEL_HEADER_ID";
41 private static final String META_DATA_KEY_FRAGMENT_CLASS =
42 "com.android.settings.FRAGMENT_CLASS";
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080043 private static final String META_DATA_KEY_PARENT_TITLE =
44 "com.android.settings.PARENT_FRAGMENT_TITLE";
45 private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
46 "com.android.settings.PARENT_FRAGMENT_CLASS";
47
48 private static final String SAVE_KEY_CURRENT_HEADER = "com.android.settings.CURRENT_HEADER";
49 private static final String SAVE_KEY_PARENT_HEADER = "com.android.settings.PARENT_HEADER";
Amith Yamasani5203bdf2010-11-04 09:59:44 -070050
51 private String mFragmentClass;
52 private int mTopLevelHeaderId;
Amith Yamasani3965ae62010-11-15 14:45:19 -080053 private Header mFirstHeader;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080054 private Header mCurrentHeader;
55 private Header mParentHeader;
56 private boolean mInLocalHeaderSwitch;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070057
Amith Yamasani02cf71a2010-09-21 15:48:52 -070058 // TODO: Update Call Settings based on airplane mode state.
Amith Yamasanib61cf512010-09-12 08:17:50 -070059
Amith Yamasani5203bdf2010-11-04 09:59:44 -070060 protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
61
62 @Override
63 protected void onCreate(Bundle savedInstanceState) {
64 getMetaData();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080065 mInLocalHeaderSwitch = true;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070066 super.onCreate(savedInstanceState);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080067 mInLocalHeaderSwitch = false;
Amith Yamasani5203bdf2010-11-04 09:59:44 -070068
Amith Yamasani72aa19d2010-12-09 06:07:12 -080069 if (!onIsHidingHeaders() && onIsMultiPane()) {
70 highlightHeader();
71 // Force the title so that it doesn't get overridden by a direct launch of
72 // a specific settings screen.
73 setTitle(R.string.settings_label);
74 }
Amith Yamasanic9fdfa82010-12-14 14:38:16 -080075
76 // Retrieve any saved state
77 if (savedInstanceState != null) {
78 mCurrentHeader = savedInstanceState.getParcelable(SAVE_KEY_CURRENT_HEADER);
79 mParentHeader = savedInstanceState.getParcelable(SAVE_KEY_PARENT_HEADER);
80 }
81
82 // If the current header was saved, switch to it
83 if (savedInstanceState != null && mCurrentHeader != null) {
84 //switchToHeaderLocal(mCurrentHeader);
85 showBreadCrumbs(mCurrentHeader.title, null);
86 }
87
88 if (mParentHeader != null) {
89 setParentTitle(mParentHeader.title, null, new OnClickListener() {
90 public void onClick(View v) {
91 switchToParent(mParentHeader.fragment);
92 }
93 });
94 }
95 }
96
97 @Override
98 protected void onSaveInstanceState(Bundle outState) {
99 super.onSaveInstanceState(outState);
100
101 // Save the current fragment, if it is the same as originally launched
102 if (mCurrentHeader != null) {
103 outState.putParcelable(SAVE_KEY_CURRENT_HEADER, mCurrentHeader);
104 }
105 if (mParentHeader != null) {
106 outState.putParcelable(SAVE_KEY_PARENT_HEADER, mParentHeader);
107 }
108 }
109
110 private void switchToHeaderLocal(Header header) {
111 mInLocalHeaderSwitch = true;
112 switchToHeader(header);
113 mInLocalHeaderSwitch = false;
114 }
115
116 @Override
117 public void switchToHeader(Header header) {
118 if (!mInLocalHeaderSwitch) {
119 mCurrentHeader = null;
120 mParentHeader = null;
121 }
122 super.switchToHeader(header);
123 }
124
125 /**
126 * Switch to parent fragment and store the grand parent's info
Jake Hamby2748fc22011-01-12 15:06:28 -0800127 * @param className name of the activity wrapper for the parent fragment.
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800128 */
129 private void switchToParent(String className) {
130 final ComponentName cn = new ComponentName(this, className);
131 try {
132 final PackageManager pm = getPackageManager();
133 final ActivityInfo parentInfo = pm.getActivityInfo(cn, PackageManager.GET_META_DATA);
134
135 if (parentInfo != null && parentInfo.metaData != null) {
136 String fragmentClass = parentInfo.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
137 CharSequence fragmentTitle = parentInfo.loadLabel(pm);
138 Header parentHeader = new Header();
139 parentHeader.fragment = fragmentClass;
140 parentHeader.title = fragmentTitle;
141 mCurrentHeader = parentHeader;
142
143 switchToHeaderLocal(parentHeader);
144
145 mParentHeader = new Header();
146 mParentHeader.fragment
147 = parentInfo.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
148 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
149 }
150 } catch (NameNotFoundException nnfe) {
151 Log.w("Settings", "Could not find parent activity : " + className);
152 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700153 }
154
Amith Yamasani3965ae62010-11-15 14:45:19 -0800155 @Override
156 public void onNewIntent(Intent intent) {
157 super.onNewIntent(intent);
158
159 // If it is not launched from history, then reset to top-level
160 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0
161 && mFirstHeader != null) {
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800162 switchToHeaderLocal(mFirstHeader);
Amith Yamasani3965ae62010-11-15 14:45:19 -0800163 }
164 }
165
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700166 private void highlightHeader() {
167 if (mTopLevelHeaderId != 0) {
168 Integer index = mHeaderIndexMap.get(mTopLevelHeaderId);
169 if (index != null) {
170 getListView().setItemChecked(index, true);
171 }
172 }
173 }
174
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700175 @Override
176 public Intent getIntent() {
177 String startingFragment = getStartingFragmentClass(super.getIntent());
178 if (startingFragment != null && !onIsMultiPane()) {
179 Intent modIntent = new Intent(super.getIntent());
180 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700181 Bundle args = super.getIntent().getExtras();
182 if (args != null) {
183 args = new Bundle(args);
184 } else {
185 args = new Bundle();
186 }
187 args.putParcelable("intent", super.getIntent());
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700188 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, super.getIntent().getExtras());
189 return modIntent;
190 }
191 return super.getIntent();
192 }
193
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700194 /**
Amith Yamasani379d9b02010-09-27 12:03:59 -0700195 * Checks if the component name in the intent is different from the Settings class and
196 * returns the class name to load as a fragment.
197 */
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700198 protected String getStartingFragmentClass(Intent intent) {
199 if (mFragmentClass != null) return mFragmentClass;
200
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700201 String intentClass = intent.getComponent().getClassName();
Amith Yamasani379d9b02010-09-27 12:03:59 -0700202 if (intentClass.equals(getClass().getName())) return null;
203
Dianne Hackbornee293792010-11-01 12:32:33 -0700204 if ("com.android.settings.ManageApplications".equals(intentClass)
205 || "com.android.settings.RunningServices".equals(intentClass)
206 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
Dianne Hackbornf4eb85b2010-10-29 16:53:04 -0700207 // Old name of manage apps.
208 intentClass = com.android.settings.applications.ManageApplications.class.getName();
209 }
210
Amith Yamasani379d9b02010-09-27 12:03:59 -0700211 return intentClass;
212 }
213
214 /**
215 * Override initial header when an activity-alias is causing Settings to be launched
216 * for a specific fragment encoded in the android:name parameter.
217 */
218 @Override
219 public Header onGetInitialHeader() {
220 String fragmentClass = getStartingFragmentClass(super.getIntent());
221 if (fragmentClass != null) {
222 Header header = new Header();
223 header.fragment = fragmentClass;
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800224 header.title = getTitle();
Amith Yamasanie0e4fc22010-10-05 11:49:51 -0700225 header.fragmentArguments = getIntent().getExtras();
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800226 mCurrentHeader = header;
Amith Yamasani379d9b02010-09-27 12:03:59 -0700227 return header;
228 }
229 return super.onGetInitialHeader();
230 }
231
Dianne Hackbornb7258182011-03-15 16:23:55 -0700232 @Override
Dianne Hackborn48147dc2011-03-18 12:29:41 -0700233 public Intent onBuildStartFragmentIntent(String fragmentName, Bundle args,
234 int titleRes, int shortTitleRes) {
235 Intent intent = super.onBuildStartFragmentIntent(fragmentName, args,
236 titleRes, shortTitleRes);
Dianne Hackbornb7258182011-03-15 16:23:55 -0700237 intent.setClass(this, SubSettings.class);
238 return intent;
239 }
240
Amith Yamasani379d9b02010-09-27 12:03:59 -0700241 /**
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700242 * Populate the activity with the top-level headers.
243 */
Amith Yamasanid7993472010-08-18 13:59:28 -0700244 @Override
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700245 public void onBuildHeaders(List<Header> target) {
246 loadHeadersFromResource(R.xml.settings_headers, target);
Amith Yamasanid7993472010-08-18 13:59:28 -0700247
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700248 updateHeaderList(target);
249 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700250
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700251 private void updateHeaderList(List<Header> target) {
252 int i = 0;
253 while (i < target.size()) {
254 Header header = target.get(i);
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700255 // Ids are integers, so downcasting
256 int id = (int) header.id;
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700257 if (id == R.id.dock_settings) {
258 if (!needsDockSettings())
259 target.remove(header);
260 } else if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
261 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
262 } else if (id == R.id.call_settings) {
263 if (!Utils.isVoiceCapable(this))
264 target.remove(header);
Amith Yamasanid7993472010-08-18 13:59:28 -0700265 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700266 // Increment if the current one wasn't removed by the Utils code.
267 if (target.get(i) == header) {
Amith Yamasani3965ae62010-11-15 14:45:19 -0800268 // Hold on to the first header, when we need to reset to the top-level
269 if (i == 0) mFirstHeader = header;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700270 mHeaderIndexMap.put(id, i);
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700271 i++;
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700272 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700273 }
274 }
275
Amith Yamasani02cf71a2010-09-21 15:48:52 -0700276 private boolean needsDockSettings() {
277 return getResources().getBoolean(R.bool.has_dock_settings);
Amith Yamasanib61cf512010-09-12 08:17:50 -0700278 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700279
280 private void getMetaData() {
281 try {
282 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
283 PackageManager.GET_META_DATA);
284 if (ai == null || ai.metaData == null) return;
285 mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
286 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
Amith Yamasanic9fdfa82010-12-14 14:38:16 -0800287
288 // Check if it has a parent specified and create a Header object
289 final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
290 String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
291 if (parentFragmentClass != null) {
292 mParentHeader = new Header();
293 mParentHeader.fragment = parentFragmentClass;
294 if (parentHeaderTitleRes != 0) {
295 mParentHeader.title = getResources().getString(parentHeaderTitleRes);
296 }
297 }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700298 } catch (NameNotFoundException nnfe) {
299 }
300 }
301
Amith Yamasani9e3a4702011-01-11 09:09:26 -0800302 @Override
303 public boolean hasNextButton() {
304 return super.hasNextButton();
305 }
306
307 @Override
308 public Button getNextButton() {
309 return super.getNextButton();
310 }
311
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700312 /*
313 * Settings subclasses for launching independently.
314 */
315
316 public static class BluetoothSettingsActivity extends Settings { }
317 public static class WirelessSettingsActivity extends Settings { }
318 public static class TetherSettingsActivity extends Settings { }
319 public static class VpnSettingsActivity extends Settings { }
320 public static class DateTimeSettingsActivity extends Settings { }
321 public static class StorageSettingsActivity extends Settings { }
322 public static class WifiSettingsActivity extends Settings { }
323 public static class InputMethodAndLanguageSettingsActivity extends Settings { }
satokc88a7ff2010-12-15 04:57:24 +0900324 public static class InputMethodConfigActivity extends Settings { }
Amith Yamasani5203bdf2010-11-04 09:59:44 -0700325 public static class InputMethodAndSubtypeEnablerActivity extends Settings { }
326 public static class LocalePickerActivity extends Settings { }
327 public static class UserDictionarySettingsActivity extends Settings { }
328 public static class SoundSettingsActivity extends Settings { }
329 public static class DisplaySettingsActivity extends Settings { }
330 public static class DeviceInfoSettingsActivity extends Settings { }
331 public static class ApplicationSettingsActivity extends Settings { }
332 public static class ManageApplicationsActivity extends Settings { }
333 public static class StorageUseActivity extends Settings { }
334 public static class DevelopmentSettingsActivity extends Settings { }
335 public static class AccessibilitySettingsActivity extends Settings { }
336 public static class SecuritySettingsActivity extends Settings { }
337 public static class PrivacySettingsActivity extends Settings { }
338 public static class DockSettingsActivity extends Settings { }
339 public static class RunningServicesActivity extends Settings { }
Amith Yamasaniea071652010-11-08 14:28:05 -0800340 public static class ManageAccountsSettingsActivity extends Settings { }
Dianne Hackborn59a48602010-11-10 23:34:52 -0800341 public static class PowerUsageSummaryActivity extends Settings { }
Amith Yamasani43c69782010-12-01 09:04:36 -0800342 public static class AccountSyncSettingsActivity extends Settings { }
343 public static class AccountSyncSettingsInAddAccountActivity extends Settings { }
Andy Stadler3da38a02011-01-21 13:38:45 -0800344 public static class CryptKeeperSettingsActivity extends Settings { }
Amith Yamasania1d01842011-01-24 16:02:11 -0800345 public static class DeviceAdminSettingsActivity extends Settings { }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800346}