OSDN Git Service

am 9fe36302: (-s ours) am 9cb97c44: Merge "DO NOT MERGE Fix crash when device is...
[android-x86/packages-apps-Settings.git] / src / com / android / settings / Settings.java
1 /*
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
17 package com.android.settings;
18
19 import android.content.ComponentName;
20 import android.content.Intent;
21 import android.content.pm.ActivityInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.PackageManager.NameNotFoundException;
24 import android.os.Bundle;
25 import android.preference.PreferenceActivity;
26 import android.util.Log;
27 import android.view.View;
28 import android.view.View.OnClickListener;
29 import android.widget.Button;
30
31 import java.util.HashMap;
32 import java.util.List;
33
34 /**
35  * Top-level settings activity to handle single pane and double pane UI layout.
36  */
37 public class Settings extends PreferenceActivity implements ButtonBarHandler {
38
39     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";
43     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";
50
51     private String mFragmentClass;
52     private int mTopLevelHeaderId;
53     private Header mFirstHeader;
54     private Header mCurrentHeader;
55     private Header mParentHeader;
56     private boolean mInLocalHeaderSwitch;
57
58     // TODO: Update Call Settings based on airplane mode state.
59
60     protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
61
62     @Override
63     protected void onCreate(Bundle savedInstanceState) {
64         getMetaData();
65         mInLocalHeaderSwitch = true;
66         super.onCreate(savedInstanceState);
67         mInLocalHeaderSwitch = false;
68
69         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         }
75
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
127      * @param className name of the activity wrapper for the parent fragment.
128      */
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         }
153     }
154
155     @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) {
162             switchToHeaderLocal(mFirstHeader);
163         }
164     }
165
166     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
175     @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);
181             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());
188             modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, super.getIntent().getExtras());
189             return modIntent;
190         }
191         return super.getIntent();
192     }
193
194     /**
195      * 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      */
198     protected String getStartingFragmentClass(Intent intent) {
199         if (mFragmentClass != null) return mFragmentClass;
200
201         String intentClass = intent.getComponent().getClassName();
202         if (intentClass.equals(getClass().getName())) return null;
203
204         if ("com.android.settings.ManageApplications".equals(intentClass)
205                 || "com.android.settings.RunningServices".equals(intentClass)
206                 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
207             // Old name of manage apps.
208             intentClass = com.android.settings.applications.ManageApplications.class.getName();
209         }
210
211         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;
224             header.title = getTitle();
225             header.fragmentArguments = getIntent().getExtras();
226             mCurrentHeader = header;
227             return header;
228         }
229         return super.onGetInitialHeader();
230     }
231
232     /**
233      * Populate the activity with the top-level headers.
234      */
235     @Override
236     public void onBuildHeaders(List<Header> target) {
237         loadHeadersFromResource(R.xml.settings_headers, target);
238
239         updateHeaderList(target);
240     }
241
242     private void updateHeaderList(List<Header> target) {
243         int i = 0;
244         while (i < target.size()) {
245             Header header = target.get(i);
246             // Ids are integers, so downcasting
247             int id = (int) header.id;
248             if (id == R.id.dock_settings) {
249                 if (!needsDockSettings())
250                     target.remove(header);
251             } else if (id == R.id.operator_settings || id == R.id.manufacturer_settings) {
252                 Utils.updateHeaderToSpecificActivityFromMetaDataOrRemove(this, target, header);
253             } else if (id == R.id.call_settings) {
254                 if (!Utils.isVoiceCapable(this))
255                     target.remove(header);
256             }
257             // Increment if the current one wasn't removed by the Utils code.
258             if (target.get(i) == header) {
259                 // Hold on to the first header, when we need to reset to the top-level
260                 if (i == 0) mFirstHeader = header;
261                 mHeaderIndexMap.put(id, i);
262                 i++;
263             }
264         }
265     }
266
267     private boolean needsDockSettings() {
268         return getResources().getBoolean(R.bool.has_dock_settings);
269     }
270
271     private void getMetaData() {
272         try {
273             ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(),
274                     PackageManager.GET_META_DATA);
275             if (ai == null || ai.metaData == null) return;
276             mTopLevelHeaderId = ai.metaData.getInt(META_DATA_KEY_HEADER_ID);
277             mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
278             
279             // Check if it has a parent specified and create a Header object
280             final int parentHeaderTitleRes = ai.metaData.getInt(META_DATA_KEY_PARENT_TITLE);
281             String parentFragmentClass = ai.metaData.getString(META_DATA_KEY_PARENT_FRAGMENT_CLASS);
282             if (parentFragmentClass != null) {
283                 mParentHeader = new Header();
284                 mParentHeader.fragment = parentFragmentClass;
285                 if (parentHeaderTitleRes != 0) {
286                     mParentHeader.title = getResources().getString(parentHeaderTitleRes);
287                 }
288             }
289         } catch (NameNotFoundException nnfe) {
290         }
291     }
292
293     @Override
294     public boolean hasNextButton() {
295         return super.hasNextButton();
296     }
297
298     @Override
299     public Button getNextButton() {
300         return super.getNextButton();
301     }
302
303     /*
304      * Settings subclasses for launching independently.
305      */
306
307     public static class BluetoothSettingsActivity extends Settings { }
308     public static class WirelessSettingsActivity extends Settings { }
309     public static class TetherSettingsActivity extends Settings { }
310     public static class VpnSettingsActivity extends Settings { }
311     public static class DateTimeSettingsActivity extends Settings { }
312     public static class StorageSettingsActivity extends Settings { }
313     public static class WifiSettingsActivity extends Settings { }
314     public static class InputMethodAndLanguageSettingsActivity extends Settings { }
315     public static class InputMethodConfigActivity extends Settings { }
316     public static class InputMethodAndSubtypeEnablerActivity extends Settings { }
317     public static class LocalePickerActivity extends Settings { }
318     public static class UserDictionarySettingsActivity extends Settings { }
319     public static class SoundSettingsActivity extends Settings { }
320     public static class DisplaySettingsActivity extends Settings { }
321     public static class DeviceInfoSettingsActivity extends Settings { }
322     public static class ApplicationSettingsActivity extends Settings { }
323     public static class ManageApplicationsActivity extends Settings { }
324     public static class StorageUseActivity extends Settings { }
325     public static class DevelopmentSettingsActivity extends Settings { }
326     public static class AccessibilitySettingsActivity extends Settings { }
327     public static class SecuritySettingsActivity extends Settings { }
328     public static class PrivacySettingsActivity extends Settings { }
329     public static class DockSettingsActivity extends Settings { }
330     public static class RunningServicesActivity extends Settings { }
331     public static class ManageAccountsSettingsActivity extends Settings { }
332     public static class PowerUsageSummaryActivity extends Settings { }
333     public static class AccountSyncSettingsActivity extends Settings { }
334     public static class AccountSyncSettingsInAddAccountActivity extends Settings { }
335     public static class CryptKeeperSettingsActivity extends Settings { }
336     public static class DeviceAdminSettingsActivity extends Settings { }
337 }