blob: cc3f7ea258f33fffa1ad7a30c17052c8b8182b81 [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);
238 Utils.updatePreferenceToSpecificActivityOrRemove(activity, parent,
239 KEY_SYNC_SETTINGS, 0);
Amith Yamasanid7993472010-08-18 13:59:28 -0700240 Preference dockSettings = parent.findPreference(KEY_DOCK_SETTINGS);
241 if (activity.getResources().getBoolean(R.bool.has_dock_settings) == false
242 && dockSettings != null) {
243 parent.removePreference(dockSettings);
244 }
245
246 Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(activity, parent,
247 KEY_OPERATOR_SETTINGS);
248 Utils.updatePreferenceToSpecificActivityFromMetaDataOrRemove(activity, parent,
249 KEY_MANUFACTURER_SETTINGS);
Amith Yamasani60133dd2010-09-11 14:17:31 -0700250
251 Preference callSettings = parent.findPreference(KEY_CALL_SETTINGS);
252 if (!Utils.isVoiceCapable(activity) && callSettings != null) {
253 parent.removePreference(callSettings);
254 }
Amith Yamasanid7993472010-08-18 13:59:28 -0700255 }
256
257 @Override
258 public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
259 // If it is a fragment preference, replace the prefs pane in the 2 pane UI.
260 final String fragmentClass = preference.getFragment();
261 if (fragmentClass != null) {
262 boolean showed = ((Settings) getActivity()).showFragment(preference);
263 if (showed) {
264 highlight(preference);
265 }
266 return showed;
267 }
268 return false;
269 }
270
271 void highlight(Preference preference) {
272 if (mHighlightedPreference != null) {
273 mHighlightedPreference.setHighlighted(false);
274 }
275 mHighlightedPreference = (IconPreferenceScreen) preference;
276 mHighlightedPreference.setHighlighted(true);
277 }
278
279 void selectFirst() {
280 Preference first = getPreferenceScreen().getPreference(0);
281 onPreferenceTreeClick(getPreferenceScreen(), first);
282 }
283 }
Amith Yamasanib61cf512010-09-12 08:17:50 -0700284
285 public static class BreadCrumbs extends LinearLayout implements OnClickListener {
286
287 private ArrayList<CharSequence> mTitles = new ArrayList<CharSequence>();
288 private TextView mLevelUpTitle;
289 private TextView mCurrentLevelTitle;
290 private View mDivider;
291 private Activity mActivity;
292
293 public BreadCrumbs(Context context) {
294 this(context, null);
295 }
296
297 public BreadCrumbs(Context context, AttributeSet attrs) {
298 super(context, attrs);
299 }
300
301 public void push(CharSequence title) {
302 if (mTitles.size() == 0
303 || !TextUtils.equals(title, mTitles.get(mTitles.size() - 1))) {
304 mTitles.add(title);
305 update();
306 }
307 }
308
309 public void pop() {
310 if (mTitles.size() > 0) {
311 mTitles.remove(mTitles.size() - 1);
312 }
313 }
314
315 public void pop(CharSequence title) {
316 if (mTitles.size() > 1) {
317 mTitles.remove(title);
318 }
319 }
320
321 public void clear() {
322 mTitles.clear();
323 }
324
325 private void initNavViews() {
326 if (mLevelUpTitle == null) {
327 mLevelUpTitle = (TextView) findViewById(R.id.level_up_title);
328 mCurrentLevelTitle = (TextView) findViewById(R.id.level_current_title);
329 mDivider = findViewById(R.id.level_divider);
330 if (mLevelUpTitle != null) {
331 mLevelUpTitle.setOnClickListener(this);
332 }
333 if (mCurrentLevelTitle != null) {
334 mCurrentLevelTitle.setOnClickListener(this);
335 }
336 }
337 }
338
339 public void update() {
340 initNavViews();
341 if (mLevelUpTitle == null) return;
342
343 final int titleCount = mTitles.size();
344 if (titleCount > 1) {
345 mLevelUpTitle.setText(mTitles.get(titleCount - 2));
346 mLevelUpTitle.setVisibility(VISIBLE);
347 mDivider.setVisibility(VISIBLE);
348 } else {
349 mLevelUpTitle.setVisibility(GONE);
350 mDivider.setVisibility(GONE);
351 }
352 if (titleCount > 0) {
353 mCurrentLevelTitle.setText(mTitles.get(titleCount - 1));
354 } else {
355 mCurrentLevelTitle.setText("");
356 }
357 }
358
359 public void setActivity(Activity activity) {
360 mActivity = activity;
361 }
362
363 public void onClick(View v) {
364 if (mActivity == null)
365 return;
366 if (v == mLevelUpTitle) {
367 mActivity.onBackPressed();
368 }
369 }
370 }
The Android Open Source Projectafc4ab22009-03-03 19:32:34 -0800371}