blob: 224aa5372ab75bea2ec893d99da9b3aaa881527b [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 Yamasanid7993472010-08-18 13:59:28 -070019import android.app.Activity;
20import android.app.Fragment;
Amith Yamasanib61cf512010-09-12 08:17:50 -070021import android.content.Context;
Amith Yamasanid7993472010-08-18 13:59:28 -070022import android.content.Intent;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080023import android.os.Bundle;
Amith Yamasani0e2ab4f2010-01-14 16:12:21 -080024import android.preference.Preference;
Amith Yamasanid7993472010-08-18 13:59:28 -070025import android.preference.PreferenceFragment;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080026import android.preference.PreferenceGroup;
Amith Yamasanid7993472010-08-18 13:59:28 -070027import android.preference.PreferenceScreen;
28import android.text.TextUtils;
Amith Yamasanib61cf512010-09-12 08:17:50 -070029import android.util.AttributeSet;
Amith Yamasanid7993472010-08-18 13:59:28 -070030import android.util.Log;
Amith Yamasanib61cf512010-09-12 08:17:50 -070031import android.view.LayoutInflater;
Amith Yamasanid7993472010-08-18 13:59:28 -070032import android.view.View;
Amith Yamasanib61cf512010-09-12 08:17:50 -070033import android.view.View.OnClickListener;
34import android.widget.LinearLayout;
35import android.widget.TextView;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080036
Amith Yamasanid7993472010-08-18 13:59:28 -070037import java.util.ArrayList;
38
39/**
40 * Top-level settings activity to handle single pane and double pane UI layout.
41 */
42public class Settings extends Activity
43 implements PreferenceFragment.OnPreferenceStartFragmentCallback,
Daisuke Miyakawab5647c52010-09-10 18:04:02 -070044 SettingsPreferenceFragment.OnStateListener,
45 SettingsPreferenceFragment.FragmentStarter {
Amith Yamasanid7993472010-08-18 13:59:28 -070046
Amith Yamasanib61cf512010-09-12 08:17:50 -070047 private static final boolean DBG = false;
48
Amith Yamasanid7993472010-08-18 13:59:28 -070049 private static final String TAG = "Settings";
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080050
51 private static final String KEY_PARENT = "parent";
52 private static final String KEY_CALL_SETTINGS = "call_settings";
53 private static final String KEY_SYNC_SETTINGS = "sync_settings";
Bjorn Bringerta9d5be12009-04-27 15:16:25 +010054 private static final String KEY_SEARCH_SETTINGS = "search_settings";
Amith Yamasani0e2ab4f2010-01-14 16:12:21 -080055 private static final String KEY_DOCK_SETTINGS = "dock_settings";
Amith Yamasanid7993472010-08-18 13:59:28 -070056
Anders Hammar1b2dd9032010-04-08 10:03:50 +020057 private static final String KEY_OPERATOR_SETTINGS = "operator_settings";
58 private static final String KEY_MANUFACTURER_SETTINGS = "manufacturer_settings";
59
Amith Yamasanid7993472010-08-18 13:59:28 -070060 public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment";
Chouting Zhang5ee06352009-07-22 22:51:40 -050061
Amith Yamasanid7993472010-08-18 13:59:28 -070062 public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args";
Amith Yamasani0e2ab4f2010-01-14 16:12:21 -080063
Amith Yamasanid7993472010-08-18 13:59:28 -070064 private static final String BACK_STACK_PREFS = ":settings:prefs";
Anders Hammar1b2dd9032010-04-08 10:03:50 +020065
Amith Yamasanid7993472010-08-18 13:59:28 -070066 private View mPrefsPane;
67 private View mMainPane;
68 private boolean mSinglePane;
69
Amith Yamasanib61cf512010-09-12 08:17:50 -070070 private BreadCrumbs mBreadCrumbs;
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -080071
Amith Yamasanid7993472010-08-18 13:59:28 -070072 @Override
73 protected void onCreate(Bundle savedInstanceState) {
74 super.onCreate(savedInstanceState);
75 setContentView(R.layout.settings_top_level);
76 mPrefsPane = findViewById(R.id.prefs);
77 mMainPane = findViewById(R.id.top_level);
78 mSinglePane = mMainPane == null;
79 if (mSinglePane) mMainPane = mPrefsPane;
80
81 final Intent intent = getIntent();
82 String initialFragment = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
83 Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
84
Amith Yamasanib61cf512010-09-12 08:17:50 -070085 createActionBar();
86
Amith Yamasanid7993472010-08-18 13:59:28 -070087 if (mSinglePane) {
88 if (initialFragment != null) {
89 showFragment(initialFragment, initialArguments);
90 } else {
Daisuke Miyakawa0cc35e42010-08-24 15:50:43 -070091 // Intent#getCompontent() lets us get Fragment name, even when the Intent is
92 // given via <activity-alias>.
93 //
94 // e.g. When we reach here via "ChildSetting" activity-alias,
95 // we should get the name here instead of targetActivity ("Settings").
Amith Yamasanid7993472010-08-18 13:59:28 -070096 if (intent.getComponent().getClassName().equals(this.getClass().getName())) {
97 showFragment(TopLevelSettings.class.getName(), null);
98 } else {
99 showFragment(intent.getComponent().getClassName(), intent.getExtras());
100 }
101 }
102 } else {
103 if (!intent.getComponent().getClassName().equals(this.getClass().getName())) {
104 if (showFragment(intent.getComponent().getClassName(), intent.getExtras())) {
105 mMainPane.setVisibility(View.GONE);
106 }
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -0700107 } else {
108 Fragment topLevel = getFragmentManager().findFragmentById(R.id.top_level);
109 if (topLevel != null) {
110 ((TopLevelSettings) topLevel).selectFirst();
111 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700112 }
113 }
114 }
115
Amith Yamasanib61cf512010-09-12 08:17:50 -0700116 private void createActionBar() {
117 LayoutInflater inflater = (LayoutInflater)
118 getSystemService(Context.LAYOUT_INFLATER_SERVICE);
119 View customNavBar = inflater.inflate(R.layout.settings_actionbar, null, false);
120 getActionBar().setCustomNavigationMode(customNavBar);
121 mBreadCrumbs = (BreadCrumbs) customNavBar.findViewById(R.id.bread_crumbs);
122 mBreadCrumbs.setActivity(this);
123 }
124
Amith Yamasanid7993472010-08-18 13:59:28 -0700125 boolean showFragment(Preference preference) {
126 if (mSinglePane) {
127 startWithFragment(preference.getFragment(), preference.getExtras());
128 return false;
129 } else {
Amith Yamasanib61cf512010-09-12 08:17:50 -0700130 mBreadCrumbs.clear();
Amith Yamasanid7993472010-08-18 13:59:28 -0700131 return showFragment(preference.getFragment(), preference.getExtras());
132 }
133 }
134
135 private void startWithFragment(String fragmentName, Bundle args) {
136 Intent intent = new Intent(Intent.ACTION_MAIN);
137 intent.setClass(this, getClass());
138 intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
139 intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
140 startActivity(intent);
141 }
142
143 private boolean showFragment(String fragmentClass, Bundle extras) {
Amith Yamasanib61cf512010-09-12 08:17:50 -0700144 if (DBG) Log.d(TAG, "showFragment");
145 Fragment f = Fragment.instantiate(this, fragmentClass, extras);
Amith Yamasani60133dd2010-09-11 14:17:31 -0700146 if (f instanceof SettingsPreferenceFragment) {
Daisuke Miyakawab5647c52010-09-10 18:04:02 -0700147 SettingsPreferenceFragment spf = (SettingsPreferenceFragment) f;
148 spf.setOnStateListener(this);
149 spf.setFragmentStarter(this);
Amith Yamasanid7993472010-08-18 13:59:28 -0700150 }
Amith Yamasanib61cf512010-09-12 08:17:50 -0700151 mBreadCrumbs.clear();
152 getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
Amith Yamasani60133dd2010-09-11 14:17:31 -0700153 getFragmentManager().openTransaction().replace(R.id.prefs, f).commit();
154 return true;
Amith Yamasanid7993472010-08-18 13:59:28 -0700155 }
156
157 private void addToBreadCrumbs(Fragment fragment) {
158 final CharSequence title = ((PreferenceFragment) fragment)
159 .getPreferenceScreen().getTitle();
Amith Yamasanib61cf512010-09-12 08:17:50 -0700160 if (mSinglePane) {
161 mBreadCrumbs.clear();
Amith Yamasanid7993472010-08-18 13:59:28 -0700162 }
Amith Yamasanib61cf512010-09-12 08:17:50 -0700163 mBreadCrumbs.push(title);
Amith Yamasanid7993472010-08-18 13:59:28 -0700164 }
165
166 private void removeFromBreadCrumbs(Fragment fragment) {
Amith Yamasanib61cf512010-09-12 08:17:50 -0700167 mBreadCrumbs.pop(((PreferenceFragment) fragment).getPreferenceScreen().getTitle());
168 mBreadCrumbs.update();
Amith Yamasanid7993472010-08-18 13:59:28 -0700169 }
170
171 public void onCreated(SettingsPreferenceFragment fragment) {
Amith Yamasanib61cf512010-09-12 08:17:50 -0700172 if (DBG) Log.d(TAG, "Fragment created " + fragment);
Amith Yamasanid7993472010-08-18 13:59:28 -0700173 addToBreadCrumbs(fragment);
174 }
175
176 public void onDestroyed(SettingsPreferenceFragment fragment) {
Daisuke Miyakawa9c8bde52010-08-25 11:58:37 -0700177 Log.d(TAG, "Fragment destroyed " + fragment + " (name: " + fragment.getClass() + ")");
Amith Yamasanid7993472010-08-18 13:59:28 -0700178 }
179
180 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
Amith Yamasanib61cf512010-09-12 08:17:50 -0700181 if (DBG) Log.d(TAG, "onPreferenceStartFragment");
Daisuke Miyakawab5647c52010-09-10 18:04:02 -0700182 return startFragment(caller, pref.getFragment(), -1, pref.getExtras());
183 }
184
185 public boolean startFragment(
186 Fragment caller, String fragmentClass, int requestCode, Bundle extras) {
187 Fragment f = Fragment.instantiate(this, fragmentClass, extras);
188 caller.setTargetFragment(f, requestCode);
Amith Yamasanid7993472010-08-18 13:59:28 -0700189 if (f instanceof SettingsPreferenceFragment) {
Daisuke Miyakawab5647c52010-09-10 18:04:02 -0700190 SettingsPreferenceFragment spf = (SettingsPreferenceFragment) f;
191 spf.setOnStateListener(this);
192 spf.setFragmentStarter(this);
Amith Yamasanid7993472010-08-18 13:59:28 -0700193 }
194 getFragmentManager().openTransaction().replace(R.id.prefs, f)
195 .addToBackStack(BACK_STACK_PREFS).commit();
196 return true;
197 }
198
Amith Yamasanib61cf512010-09-12 08:17:50 -0700199 @Override
200 public void onBackPressed() {
201 mBreadCrumbs.pop();
202 mBreadCrumbs.update();
203 super.onBackPressed();
204 }
205
Amith Yamasanid7993472010-08-18 13:59:28 -0700206 public static class TopLevelSettings extends PreferenceFragment {
207
208 private IconPreferenceScreen mHighlightedPreference;
209
210 @Override
211 public void onCreate(Bundle savedInstanceState) {
212 super.onCreate(savedInstanceState);
213
214 // Load the preferences from an XML resource
215 addPreferencesFromResource(R.xml.settings);
216
217 updatePreferenceList();
218 }
219
Amith Yamasanib61cf512010-09-12 08:17:50 -0700220 @Override
221 public void onResume() {
222 super.onResume();
223
224 updateCallSettings();
225 }
226
227 private void updateCallSettings() {
228 Preference callSettings = findPreference(KEY_CALL_SETTINGS);
229 // Might have been removed in non-voice-capable devices
230 if (callSettings != null) {
231 callSettings.setEnabled(!AirplaneModeEnabler.isAirplaneModeOn(getActivity()));
232 }
233 }
234
Amith Yamasanid7993472010-08-18 13:59:28 -0700235 private void updatePreferenceList() {
236 final Activity activity = getActivity();
237 PreferenceGroup parent = (PreferenceGroup) findPreference(KEY_PARENT);
Amith Yamasanid7993472010-08-18 13:59:28 -0700238 Preference dockSettings = parent.findPreference(KEY_DOCK_SETTINGS);
239 if (activity.getResources().getBoolean(R.bool.has_dock_settings) == false
240 && dockSettings != null) {
241 parent.removePreference(dockSettings);
242 }
243
244 Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(activity, parent,
245 KEY_OPERATOR_SETTINGS);
246 Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(activity, parent,
247 KEY_MANUFACTURER_SETTINGS);
Amith Yamasani60133dd2010-09-11 14:17:31 -0700248
249 Preference callSettings = parent.findPreference(KEY_CALL_SETTINGS);
250 if (!Utils.isVoiceCapable(activity) && callSettings != null) {
251 parent.removePreference(callSettings);
252 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700253 }
254
255 @Override
256 public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
257 // If it is a fragment preference, replace the prefs pane in the 2 pane UI.
258 final String fragmentClass = preference.getFragment();
259 if (fragmentClass != null) {
260 boolean showed = ((Settings) getActivity()).showFragment(preference);
261 if (showed) {
262 highlight(preference);
263 }
264 return showed;
265 }
266 return false;
267 }
268
269 void highlight(Preference preference) {
270 if (mHighlightedPreference != null) {
271 mHighlightedPreference.setHighlighted(false);
272 }
273 mHighlightedPreference = (IconPreferenceScreen) preference;
274 mHighlightedPreference.setHighlighted(true);
275 }
276
277 void selectFirst() {
278 Preference first = getPreferenceScreen().getPreference(0);
279 onPreferenceTreeClick(getPreferenceScreen(), first);
280 }
281 }
Amith Yamasanib61cf512010-09-12 08:17:50 -0700282
283 public static class BreadCrumbs extends LinearLayout implements OnClickListener {
284
285 private ArrayList<CharSequence> mTitles = new ArrayList<CharSequence>();
286 private TextView mLevelUpTitle;
287 private TextView mCurrentLevelTitle;
288 private View mDivider;
289 private Activity mActivity;
290
291 public BreadCrumbs(Context context) {
292 this(context, null);
293 }
294
295 public BreadCrumbs(Context context, AttributeSet attrs) {
296 super(context, attrs);
297 }
298
299 public void push(CharSequence title) {
300 if (mTitles.size() == 0
301 || !TextUtils.equals(title, mTitles.get(mTitles.size() - 1))) {
302 mTitles.add(title);
303 update();
304 }
305 }
306
307 public void pop() {
308 if (mTitles.size() > 0) {
309 mTitles.remove(mTitles.size() - 1);
310 }
311 }
312
313 public void pop(CharSequence title) {
314 if (mTitles.size() > 1) {
315 mTitles.remove(title);
316 }
317 }
318
319 public void clear() {
320 mTitles.clear();
321 }
322
323 private void initNavViews() {
324 if (mLevelUpTitle == null) {
325 mLevelUpTitle = (TextView) findViewById(R.id.level_up_title);
326 mCurrentLevelTitle = (TextView) findViewById(R.id.level_current_title);
327 mDivider = findViewById(R.id.level_divider);
328 if (mLevelUpTitle != null) {
329 mLevelUpTitle.setOnClickListener(this);
330 }
331 if (mCurrentLevelTitle != null) {
332 mCurrentLevelTitle.setOnClickListener(this);
333 }
334 }
335 }
336
337 public void update() {
338 initNavViews();
339 if (mLevelUpTitle == null) return;
340
341 final int titleCount = mTitles.size();
342 if (titleCount > 1) {
343 mLevelUpTitle.setText(mTitles.get(titleCount - 2));
344 mLevelUpTitle.setVisibility(VISIBLE);
345 mDivider.setVisibility(VISIBLE);
346 } else {
347 mLevelUpTitle.setVisibility(GONE);
348 mDivider.setVisibility(GONE);
349 }
350 if (titleCount > 0) {
351 mCurrentLevelTitle.setText(mTitles.get(titleCount - 1));
352 } else {
353 mCurrentLevelTitle.setText("");
354 }
355 }
356
357 public void setActivity(Activity activity) {
358 mActivity = activity;
359 }
360
361 public void onClick(View v) {
362 if (mActivity == null)
363 return;
364 if (v == mLevelUpTitle) {
365 mActivity.onBackPressed();
366 }
367 }
368 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800369}